EMZETT.
Login

Kurz: Modernes Java bietet kompakte Mittel für Datenklassen und feste Wertemengen.

Teil des Kurses Java

Kapitel 13 von 22 im Kurs Java. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Modernes Java bietet kompakte Mittel für Datenklassen und feste Wertemengen.

Records: Datenklassen in einer Zeile

Ein Record (ab Java 16) ist eine unveränderliche Datenklasse. Der Compiler erzeugt Konstruktor, Zugriffsmethoden, equals, hashCode und toString:

public class Aufnahme {
    record Person(String name, int alter) {
        Person {                                      // kompakter Konstruktor: Prüfung
            if (alter < 0) throw new IllegalArgumentException("Alter < 0");
        }
        String gruss() { return "Hallo, ich bin " + name; }
        static Person kind(String name) { return new Person(name, 0); }
    }
 
    public static void main(String[] args) {
        Person mia = new Person("Mia", 17);
        System.out.println(mia);                       // toString automatisch
        System.out.println(mia.name() + " " + mia.alter() + " " + mia.gruss());
        System.out.println(mia.equals(new Person("Mia", 17)) + " " + Person.kind("Tom"));
        try { new Person("X", -1); } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); }
    }
}

Ausgabe:

Person[name=Mia, alter=17]
Mia 17 Hallo, ich bin Mia
true Person[name=Tom, alter=0]
Alter < 0

Records eignen sich für Daten, die nur transportiert werden: Rückgabewerte, Nachrichten, Konfiguration. Sie sind flach unveränderlich (Felder final).

Enums: feste Wertemengen

Ein Enum ist ein Typ mit einer festen Menge benannter Konstanten:

public class Wochentage {
    enum Tag { MONTAG, DIENSTAG, MITTWOCH, DONNERSTAG, FREITAG, SAMSTAG, SONNTAG }
 
    enum Planet {
        MERKUR(3.303e+23, 2.4397e6), ERDE(5.976e+24, 6.37814e6);
        private final double masse, radius;
        Planet(double masse, double radius) { this.masse = masse; this.radius = radius; }
        double oberflaechengewicht(double m) { return m * 6.67300E-11 * masse / (radius * radius); }
    }
 
    public static void main(String[] args) {
        Tag t = Tag.FREITAG;
        System.out.println(t + " " + t.ordinal() + " " + Tag.valueOf("SONNTAG") + " " + Tag.values().length);
        boolean wochenende = switch (t) { case SAMSTAG, SONNTAG -> true; default -> false; };
        System.out.println(wochenende);
        for (Planet p : Planet.values()) System.out.printf("%s: %.2f%n", p, p.oberflaechengewicht(70));
        System.out.println(Tag.valueOf("MONTAG").compareTo(Tag.DONNERSTAG));
    }
}

Ausgabe:

FREITAG 4 SONNTAG 7
false
MERKUR: 259.21
ERDE: 686.19
-3

Enums können Felder, Konstruktoren und Methoden haben und Interfaces umsetzen. EnumMap und EnumSet sind besonders effiziente Collections für Enums.

Sealed Interfaces: geschlossene Hierarchien

Mit sealed legst du fest, welche Klassen erlaubt sind. In Kombination mit switch weiß der Compiler, dass alle Fälle abgedeckt sind:

public class Formen {
    sealed interface Form permits Kreis, Rechteck, Dreieck {}
    record Kreis(double r) implements Form {}
    record Rechteck(double b, double h) implements Form {}
    record Dreieck(double basis, double hoehe) implements Form {}
 
    static double flaeche(Form f) {
        return switch (f) {                                   // keine default-Zeile nötig
            case Kreis k -> Math.PI * k.r() * k.r();
            case Rechteck r -> r.b() * r.h();
            case Dreieck d -> d.basis() * d.hoehe() / 2;
        };
    }
 
    public static void main(String[] args) {
        for (Form f : new Form[] { new Kreis(1), new Rechteck(3, 4), new Dreieck(6, 5) })
            System.out.printf("%s -> %.2f%n", f, flaeche(f));
    }
}

Ausgabe:

Kreis[r=1.0] -> 3.14
Rechteck[b=3.0, h=4.0] -> 12.00
Dreieck[basis=6.0, hoehe=5.0] -> 15.00

Fügst du später eine weitere Form hinzu, meldet der Compiler jeden switch, der sie noch nicht behandelt.

Ergebnis oder Fehler

public class Ergebnis {
    sealed interface Result<T> permits Ok, Fehler {}
    record Ok<T>(T wert) implements Result<T> {}
    record Fehler<T>(String nachricht) implements Result<T> {}
 
    static Result<Integer> teile(int a, int b) {
        return b == 0 ? new Fehler<>("Division durch 0") : new Ok<>(a / b);
    }
    public static void main(String[] args) {
        for (int b : new int[] { 2, 0 }) {
            String s = switch (teile(10, b)) {
                case Ok<Integer> ok -> "Ergebnis " + ok.wert();
                case Fehler<Integer> f -> "Fehler: " + f.nachricht();
            };
            System.out.println(s);
        }
    }
}

Ausgabe:

Ergebnis 5
Fehler: Division durch 0

Record, Klasse oder Enum?

Du brauchst …Nimm
unveränderliche Daten mit Gleichheit nach Inhaltrecord
Zustand und Verhalten, veränderlichclass
feste, endliche Wertemengeenum
geschlossene Familie von Variantensealed interface + records
Fähigkeit/Vertraginterface

Merke

  • record Punkt(int x, int y) {} erzeugt Konstruktor, Getter, equals, hashCode, toString
  • Enums sind Typen mit festen Konstanten, mit Feldern und Methoden
  • sealed begrenzt erlaubte Untertypen; switch prüft Vollständigkeit
  • Records und sealed Interfaces bilden Daten mit mehreren Varianten sauber ab

Übungsaufgabe

Modelliere eine Zahlungsart als sealed Interface mit Records (Karte, PayPal, Rechnung) und eine switch-Funktion, die den Betrag mit Gebühren berechnet.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Vererbung, Interfaces und Polymorphie

Weiter: Ausnahmen (Exceptions)

Alle Kapitel: Java im Überblick