Java records und wieso du sie nutzen solltest [German]
Tags: java, beginners, german
Published: 2023-05-27 12:31:38

Falls du ein Einsteiger bist, welcher aktuell Java lernt, kennst du bereits die Basiselemente wie Klassen, Methoden, Enums und so weiter. Jedoch gibt es seit Java 16 fest im Java Funktionsumfang verankert records. Dieses kurze Tutorial wird dir erklären, was records in Java sind, sowie einige Tipps dazugeben, wie du sie in deinem nächsten Projekt verwenden kannst.
Alle Informationen in diesem Tutorial basieren auf der [Java 16 records Dokumentation](https://docs.oracle.com/en/java/javase/16/language/records.html), sowie meinen eigenen Erfahrungen.

## Was sind record?
Einfach erklärt sind records eine Abstrahierung von Java Beans. Ein record definiert automatisch einen All arguments Konstruktor und gibt public Zugriff zu allen properties des records. Ein record hat von sich aus keine weiteren Methoden. Es ist schlicht ein _dummes_ Java Objekt ohne weitere Funktionalität.

## Wie wird ein record implementiert?
Ähnlich zu Enums kann ein record Bestandteil einer Java Klasse sein oder eine eigenständige Datei darstellen.
Als Beispiel möchten wir einen Bruch (engl. fraction) definieren. Ein Bruch besteht aus einem Zähler (engl. numerator) und einem Nenner (engl. denominator). Möchten wir dieses Objekt nun als Java Klasse schreiben sieht es wie folgt aus:

```java
public class Fraction {
  private double numerator;
  private double denominator;

  public Fraction() {
    this.numerator = 0.0;
    this.denominator = 1.0;
  }

  public Fraction(double numerator, double denominator) {
    this.numerator = numerator;
    this.denominator = denominator;
  }

  public void setNumerator(double numerator) {
    this.numerator = numerator;
  }

  public double getNumerator() {
    return this.numerator;
  }

  public void setDenominator(double denominator) {
    this.denominator= denominator;
  }

  public double getDenominator() {
    return this.denominator;
  }
}
```
Wie du erkennen kannst ist dies ziemlich viel Code um lediglich eine Klasse mit zwei Attributen zu beschreiben. Und nun lass uns dasselbe als record geschrieben betrachten:

```java
public record Fraction(double numerator, double denominator) {}
```
Kurz, oder? Und das ist der wichtigste Grund für die Verwendung von records. Diese einzelne Zeile bündelt einen All Arguments Konstruktor und die beiden public Attribute numerator und denominator.
Möchtest du eine neue Instanz dieses records erzeugen, so tust du dies wie für gewöhnliche Klassen auch.

```java
Fraction fractionAsRecord = new Fraction(0.0, 1.0);
```

## Override von Konstruktoren und Getter/Setter
Falls der vordefinierte Konstruktor und die Getter/Setter Methoden deinen Use Case nicht sinnvoll abdecken, kannst du diese auch überschreiben. Für einen Konstruktor würdest du es wie folgt machen:

```java
public record Fraction(double numerator, double denominator) {
  public Fraction(double numerator, double denominator) {
    if (numerator == 0 && denominator == 0) {
      throw new java.lang.IllegalArgumentException(
        "Invalid fraction: " + numerator + "/" + denominator
      );
    }
    this.numerator = numerator;
    this.denominator = denominator;
  }
}
```
Wie du siehst, wird hier nicht wie üblich die Override Annotation benötigt. Dasselbe kann ebenfalls für die Methoden `double numerator()` oder `void numerator(double numerator)` getan werden.

## Statische Attribute und Methoden
Nun kommen wir zu einer erweiterten Funktion von records. Records geben dir die Möglichkeit statische Attribute und statische Methoden zu definieren. Für unser Beispiel möchten wir unseren Bruch durch den Wert zwei dividieren. Dafür können wir ein statisches Attribut `static double half = 2.0` und eine statische Methode `static Fraction divideByTwo(Fraction fr)` implementieren.

```java
public record Fraction(double numerator, double denominator) {
  static double half = 2;

  public static Fraction divideByTwo(Fraction fr) {
    return new Fraction(fr.numerator(), fr.denominator() * half);
  }
}
```
Die oben aufgeführte Methode kann mittels `Fraction.divideByTwo(fraction)` aufgerufen werden. Wie du sehen kannst, kannst du Records um deine benötigten Methoden erweitern, vorausgesetzt diese sind statisch. Dies gibt dir etwas mehr Flexibilität beim Einsatz von Records.

## Andere nützliche Funktionen
In der [java 16 Dokumentation](https://docs.oracle.com/en/java/javase/16/language/records.html) sind eine Anzahl weiterer erweiterter Funktionalitäten, welche ich hiermit kurz erwähne aber nicht detailliert auf alle eingehe. Du kannst diese im eben erwähnten Link im Abschnitt "Features of Record Classes" finden.
Für mich persönlich ist die Option, dass Records Interfaces implementieren können am nützlichsten. Beispielsweise kannst du einige Basis Methoden für eine Gruppe von Records definieren. Ich gebe dir ein kurzes Beispiel mit dem Interface `Mathobject`:

```java
public interface Mathobject {
  public Mathobject divideByTwo();
}
```
Wenn wir unseren Fraction Record dieses Interface implementieren lassen, können wir unsere statische Methode `divideByTwo` umschreiben. Dies sieht dann wie folgt aus:

```java
public record Fraction(double numerator, double denominator) implements Mathobject {
  static double half = 2;

  @Override
  public Fraction multiplyByTwo() {
    return new Fraction(numerator, denominator * half);
  }
}
```
Der Record überschreibt die Methode des Interface `Mathobject` und lässt uns die beiden Attribute von Fraction innerhalb der Methode nutzen, da diese nicht mehr statisch ist.

## Abschluss
Was macht Records am Ende so nützlich?
Sie produzieren signifikant weniger Boilerplate Code.
Zudem kennt jeder erfahrene Java Entwickler das Prinzip von Records und kann somit diesen übersichtlichen Code sehr leicht verstehen. Somit wird dein Code verständlicher und orderntlicher.
Und das allerwichtigste ist der Aspekt, dass du weniger Code schreiben musst, was zu einer Zeitersparnis führt.

Keep coding.

[Here you can find the english version.](https://dev.to/pythonisnotasnake/java-records-and-why-you-should-use-them-1bbn)