Java 16 ist seit heute verfügbar

Ich habe mir die Records durchgelesen und trotzdem nicht Verstanden was das jetzt für einen Vorteil bringt gegenüber einer normalen Klasse.
 
Du willst uns ehrlich erzählen, dass du nicht den Vorteil siehst von:
Java:
record Person(Date birthday, String givenName, String familyName) {}

gegenüber:
Java:
class PersonClass {
    private final Date birthday;
    private final String givenName;
    private final String familyName;

    PersonClass(Date birthday, String givenName, String familyName) {
        this.birthday = birthday;
        this.givenName = givenName;
        this.familyName = familyName;
    }

    public Date getBirthday() {
        return birthday;
    }

    public String getGivenName() {
        return givenName;
    }

    public String getFamilyName() {
        return familyName;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PersonClass that = (PersonClass) o;
        return Objects.equals(birthday, that.birthday) && Objects.equals(givenName, that.givenName) && Objects.equals(familyName, that.familyName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(birthday, givenName, familyName);
    }

    @Override
    public String toString() {
        return "PersonClass{" +
                "birthday=" + birthday +
                ", givenName='" + givenName + '\'' +
                ", familyName='" + familyName + '\'' +
                '}';
    }
}
?

Jaaaaaa, ich weiss, man kann auch Lombok verwenden, aber Lombok greift tief in Implementierungsdetails des JREs ein (interne OpenJDK Compiler Implementierungsklassen), um seinen Zweck zu erfüllen und die Java Annotation Processors waren niemals für solch einen Zweck vorgesehen.
 
Weniger Code und garantierte Immutability.
Auch werden equals/hashcode/toString automatisch generiert.
Was ist das?
Was kann man damit machen?
Davon habe ich noch nie gehört, was soll das sein?
Du hast hier sealed interfaces und somit kannst du bestimmen, welche Implementierungen es gibt und da baut pattern matching drauf auf.
Java:
switch(o) {
  case (Impl1 i) -> i.doStuffi1(); break;
  case (Impl2 i) -> i2.doStuff(); break;
  // ...
}
Auch gibt es Vereinfachung bei instanceof Prüfungen:
vorher
Java:
if (o instanceof String) {
   String s = (String) o;
   // ...
}
jetzt:
Java:
if (o instanceof String s) {
  // do stuff with s as String
}
 
Viele der Dinge die den neueren Java Versionen gekommen sind, sind eigentlich nur Dinge, die man auch schon bisher konnte. Die haben nur oft den Vorteil

* Weniger Code für das gleiche Ergebnis
* Weniger Möglichkeiten es falsch zu machen (z.B. eben für records mit equals & hashCode korrekt implementiert)
* Sind oft dadurch beim lesen des Codes aussagestärker und lesbarer (wie z.B. beim instanceof, es fallen casts und explite Definition einer lokalen Variable) weg
* Dadurch sind manche Dinge auch durch statische Code Analysen leichter prüfbarer bzw. manche statische Code-Analysen werden einfach überflüssig, weil die Konstrukte es eben verhindern Dinge falsch zu mache. (beim Instanceof kann ich nicht instanceof auf Class A machen und dann auf Class B casten => Verhindern von Fehlern)

Nachtrag, Beispiel für das letzte:

Java:
        Object a = new IllegalStateException();
        if (a instanceof IllegalStateException) {
            IllegalThreadStateException e = (IllegalThreadStateException)a;
        }
Das ist offensichtlich falsch, kann aber durch nicht aufpassen beim Autocomplete passieren. Aktuell warnt mich spotbugs:

Impossible cast from IllegalStateException to IllegalThreadStateException in klasse.main(String[]) [Scary(9), High confidence] SpotBugs Problem (Scary)

Solche Analysen werden dann überflüssig, weil man es einfach nicht mehr falsch machen kann mit den Konstrukten. Und eine Vermeidung von möglichen Fehlern ist immer gut. Denn Fehler passieren, egal wie gut man ist. Und insbesondere wird Software im Laufe der Jahre von vielen Personen von unterschiedlichen Skill-Leveln angefasst und man sollte Software so schreiben, dass die Chance, das ein Junior-Developer Fehler macht, möglichst gering ist.
 
Da hätte ich mal eine Frage:

Java:
record Person(Date birthday, String givenName, String familyName) {}

Wie siehts eigentlich aus wenn ich später feststelle, daß "Person" doch etwas mehr können muß als bloß drei Variablen zu bündeln? Z.B. wenn ich irgendwann mal das Geburtsdatum auf Plausibilität prüfen will?
Muß ich dann statt des Records doch eine richtige Klasse verwenden und danach überall, wo ich das Record verwendet habe, wieder ran, oder geht das schmerzfrei?
 
Wie siehts eigentlich aus wenn ich später feststelle, daß "Person" doch etwas mehr können muß als bloß drei Variablen zu bündeln? Z.B. wenn ich irgendwann mal das Geburtsdatum auf Plausibilität prüfen will?
Den kanonischen Konstruktor kann man "überschreiben", und Methode kann man ganz normal anlegen:

Java:
record Person(Date birthday, String givenName, String familyName) {
    Person(Date birthday, String givenName, String familyName) {
        this.givenName = givenName;
        //...
    }

    int getAge() {
        return 42;
    }
}
 

Neue Themen


Zurück
Oben