Records
Motivation
Menschen, die andere Programmiersprachen kennen sind häufig davon erstaunt, wie viel Aufwand man in Java betreiben muss, um in einer Klasse ein paar Daten zu speichern. Will man beispielsweise ein Klasse für Rechtecke schreiben, so kommt der folgende Code dabei heraus:
public final class Rectangle {
private final double length;
private final double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
public double length() { return this.length; }
public double width() { return this.width; }
@Override
public boolean equals(Object o) {
// ...
}
@Override
public int hashCode() {
// ...
}
@Override
public String toString() {
return "Rechteck{" + "length=" + length + ", width=" + width + '}';
}
}
Rectangle r = new Rectangle(4, 3);
System.out.println("Fläche: " + r.length() * r.width());
Man sieht sofort, dass der Schreibaufwand erheblich ist, obwohl es sich hier um einen absolut primitiven Datencontainer handelt.
Um das Schreiben von einfachen Datenklassen zu vereinfachen, wurde mit Java 14 die Records eingeführt.
Records
Records
- wurden mit Java 14 eingeführt
- bieten eine einfache Möglichkeit, Datenklassen zu definieren
- Syntax:
record <NAME> (<ATTRIBUTE>) { <RUMPF> }
record Rectangle(double length, double width) { }
Rectangle r = new Rectangle(4, 3);
System.out.println("Fläche: " + r.length() * r.width());
Das Ergebnis dieser Deklaration ist identisch mit dem umfangreichen Java-Code, der im Beispiel davor gegeben wurde. Im Hintergrund werden vom Java-Compiler die notwendigen Methoden ergänzt.
Generiert werden
- Klasse (
final
), abgeleitet vonjava.lang.Record
- Attribute (
final
undprivate
) - Konstruktor mit passender Signatur
- Zugriffsmethoden, die ebenso heißen, wie die Attribute
equals
- undhashCode
-MethodetoString
-Methode
final
, man kann also nicht von ihnen erben Konstruktor
Der Konstruktor von Records wird automatisch erstellt und als canonical constructor bezeichnet. Er nimmt Parameter, die den Attributen bei der Definition des Records entsprechen und weist dann die Werte zu.
Wenn man die Attribute prüfen möchte, bevor man sie zuweist, kann man einen eigenen Konstruktor schreiben, der eine entsprechende Prüfung durchführt.
- Eigener canonical constructor mit Prüfung der Parameter
record Rectangle(double length, double width) {
public Rectangle(double length, double width) {
if (length <= 0 || width <= 0) {
throw new java.lang.IllegalArgumentException(
String.format("Invalid dimensions: %f, %f", length, width));
}
this.length = length;
this.width = width;
}
}
Wenn man sich das Beispiel ansieht, fällt auf, dass die Attribute in der Record-Deklaration und im Konstruktor zwei mal angegeben werden und damit wieder unnötige Schreibarbeit entsteht. Aus diesem Grund, erlauben es Records, diese Dopplung einfach wegzulassen.
compact constructor
- Wiederholung der Parameterliste entfällt
- Zuweisung der Attribute wird weggelassen
record Rectangle(double length, double width) {
public Rectangle {
if (length <= 0 || width <= 0) {
throw new java.lang.IllegalArgumentException(
String.format("Invalid dimensions: %f, %f", length, width));
}
}
}
Bei dieser Form entfällt die Zuweisung der Konstruktor-Parameter an die Attribute und wird vom Compiler automatisch ergänzt.
Methoden
Da Records im Endeffekt normale Java-Klassen sind, bei denen der Compiler uns einen großen Teil der Arbeit abnimmt, kann man sie auch mit eigenen Methoden versehen.
Man kann eigene Methoden schreiben
- um die automatisch generierten zu ersetzen
- um neue Methoden hinzuzufügen (auch
static
)
record Rectangle(double length, double width) {
public double length() {
return length;
}
}
Das obige Beispiel ist zwar nicht besonders sinnvoll, zeigt aber die Möglichkeit, die bereits existierenden Zugriffsmethode length()
durch eine eigene Implementierung zu ersetzen.
record Rectangle(double length, double width) {
public double area() {
return length * width;
}
}