---
title: 'Inselupdate: Record-Patterns in Java 21'
url: 'https://tutego.de/blog/javainsel/2023/08/record-patterns-in-java-21'
markdown: 'https://tutego.de/blog/javainsel/2023/08/record-patterns-in-java-21.md'
date: '2023-08-26'
description: 'Führen wir für die folgenden Beispiele ein Record für Punkte ein: record Point( int x, int y ) {} Nun möchten wir überprüfen, ob die X-Y-Koordinaten eines Punktes auf null stehen. Dafür erstellen wir eine Methode namens isZeroPoint(…), die alle Objekttypen akzeptiert und false zurückgibt, wenn es s…'
taxonomy:
  category:
    - Insel
    - 'Java 21'
---

# Inselupdate: Record-Patterns in Java 21

![Illustration einer tropischen Insel mit Palmen und einem hohen Berg](https://tutego.de/blog/javainsel/user/themes/tutego/images/insel-cover.jpg)# Java Blog für Programmierer

[Java Blog für Programmierer](https://tutego.de/blog/javainsel/)

## Inselupdate: Record-Patterns in Java 21

26.08.2023 · [Christian Ullenboom](https://tutego.de/blog/javainsel/author/admin/)

Führen wir für die folgenden Beispiele ein Record für Punkte ein:

```java
record Point( int x, int y ) {}
```

Nun möchten wir überprüfen, ob die X-Y-Koordinaten eines Punktes auf `null` stehen. Dafür erstellen wir eine Methode namens `isZeroPoint(…)`, die alle Objekttypen akzeptiert und `false` zurückgibt, wenn es sich nicht um einen Punkt handelt:

```java
static boolean isZeroPoint( Point object ) {

  if ( object instanceof Point ) {

    Point point = (Point) object;

    return point.x() == 0 && point.y() == 0;

  }

  return false;

}
```

Eine kompaktere Version des Tests, die auf eine Zwischenvariable verzichtet, kann so aussehen:

```java
return object instanceof Point && ((Point) object).x() == 0 && ((Point) object).y() == 0;
```

Lesbarerer ist es nicht.

Der Einsatz einer Pattern-Variable verbessert die Lesbarkeit und Klarheit des Codes:

```java
static boolean isZeroPoint( Object object ) {

  return object instanceof Point p && p.x() == 0 && p.y() == 0;

}

Der Test p.x() == 0 && p.y() == 0 lässt sich mit einem Trick noch weiter verkürzen:
```

```java
static boolean isZeroPoint( Object object ) {

  return object instanceof Point p && (p.x() | p.y()) == 0;

}
```

Wenn zwei Zahlen mittels der bitweisen ODER-Operation verknüpft werden und eine davon nicht `null` ist, wird auch das Ergebnis nicht `null` sein. Dies ermöglicht eine elegante und kompakte Überprüfung der Nullbedingung für beide Koordinaten gleichzeitig.

#### Record-Pattern einsetzen

Auffällig an der bisherigen Lösung ist die Notwendigkeit einer `Point`-Variable p, um auf `p.x()` und `p.y()` zuzugreifen. Java 21 führt Record-Pattern[\[1\]](#_ftn1) ein, die in anderen Programmiersprachen als Destrukturierung bezeichnet werden. Record-Pattern können sowohl bei instanceof als auch bei switch verwendet werden. Hier ist ein Beispiel für instanceof, wodurch `isZeroPoint(…)` etwas kürzer wird:

```java
static boolean isZeroPoint( Point point ) {

  return point instanceof Point( int a, int b ) && (a | b) == 0;

}
```

Der Teil `Point`(int a, int b) nennt sich Record-Pattern. Nach einer Übereinstimmung werden neue lokale Variablen a und b eingeführt, die vom Punkt die Koordinaten enthalten. Das heißt, a wird mit `point.x()` und b mit `point.y()` belegt. Die Variablennamen müssen nicht mit den Record-Komponentennamen übereinstimmen; in diesem Fall heißen sie a und b, x und y wären aber möglich. Wichtig ist, alle Record-Komponenten aufzulisten; keine Record-Komponente darf ausgelassen werden.

Kommen wir von Punkten zu Linien. Betrachten wir ein neues Record:

```java
record Line( Point start, Point end ) {}
```

Schreiben wir eine zweite Methode `isZeroLine(…)`, die überprüft, ob die beiden Punkte der Linie Null sind oder nicht. Beginnen wir mit einer Pattern-Variablen:

```java
static boolean isZeroLine( Object object ) {

  return    object instanceof Line line

         && (  line.start().x() | line.start().y()

             | line.end().x()   | line.end().y() ) == 0;

}
```

Da es sich bei `Line` um einen Record handelt, kann das Record-Pattern angewendet werden:

```java
static boolean isZeroLine( Object object ) {

  return    object instanceof Line( Point start, Point end )

         && (start.x() | start.y() | end.x() | end.y()) == 0;

}
```

Die Datentypen können mit var abgekürzt werden:

```java
static boolean isZeroLine( Object object ) {

  return    object instanceof Line( var start, var end )

         && (start.x() | start.y() | end.x() | end.y()) == 0;

}
```

#### Geschachtelte Record-Pattern

Record-Pattern können auch verschachtelt werden, um komplexere Strukturen abzubilden:

```java
static boolean isZeroLine( Object object ) {

  return object instanceof Line(

    Point( int x1, int y1 ), Point( int x2, int y2 )

   ) && (x1 | y1 | x2 | y2) == 0;

}
```

Das Code-Volumen schrumpft nicht, daher ist es Geschmacksache, ob die Variante besser ist.

#### Record-Pattern bei switch

Das Pattern-Matching bei switch ist in Java 21 noch leistungsfähiger geworden. Erstellen wir eine zweite Methode `isZero(Object)`, die sowohl Punkte als auch Linien überprüfen kann. Lösen wir die Aufgabe zuerst wie bekannt mit Pattern-Variablen:

```java
static boolean isZero( Object o ) {

  return switch ( o ) {

    case Point p -> (p.x() | p.y()) == 0;

    case Line l -> (l.start().x() | l.start().y() | l.end().x() | l.end().y()) == 0;

    default -> false;

  };

}
```

Neben instanceof sind Record-Pattern auch bei switch-case möglich. Die Methode kann wie folgt umgeschrieben werden:

```java
static boolean isZero( Object o ) {

  return switch ( o ) {

    case Point( int x, int y ) -> (x | y) == 0;

    case Line( Point s, Point e ) -> isZero( s ) && isZero( e );

    default -> false;

  };

}
```

Bei der Linie lässt sich das Record-Pattern wieder schachteln:

```java
static boolean isZero( Object o ) {

  return switch ( o ) {

    ...

    case Line( Point( int x1, int y1 ), Point( int x2, int y2 ) )

          -> (x1 | y1 | x2 | y2) == 0;

    ...

  };

}
```

Allerdings ist auch hier der Code wieder länger.

#### Pattern-Matching mit Record-Pattern und when

Wir haben gesehen, dass Pattern-Matching mit Record-Pattern zur Destrukturierung möglich ist. Auch lässt sich ein when für eine weitere Abfrage einsetzen. Die Bedingung hinter when kann auf die Pattern-Variable oder Variable aus dem Record-Pattern zugreifen.

Ein Beispiel: Wir möchten `Candy` und `Book` als Records implementieren:

```java
record Candy( int calories ) {}

record Book( String title, int numberOfPages ) {}
```

Ein Block kann wie folgt Ausgaben zu unterschiedlichen Objekttypen formulieren:

```java
Object object = new Candy( 120 );

switch ( object ) {

  case Candy candy

  when candy.calories > 10_000 ->

      System.out.println( "Are you trying to sweeten the whole world?" );

  case Candy candy ->

      System.out.println("Is this candy trying to start a dance party in my mouth?");

  case Book( var title, var pages )

  when pages > 100 ->

      System.out.println(

          "Looks like someone was on a mission to make the dictionary jealous." );

  case Book( var title, var pages )

  when title.isEmpty() ->

      System.out.println("Diving into books that forgot to introduce themselves.");

  case Book -> System.out.println( "Opening minds, one page at a time" );

  default -> System.out.println("Who knew boredom could be so three-dimensional?");

};
```

Das Beispiel zeigt Pattern-Matching sowohl ohne als auch mit Record-Pattern. Auch hier müssen wir erneut die Dominanz beachten. Es wäre inkorrekt, case `Book` -> über die anderen Fallblöcke case `Book`( var title, var pages ) when … zu setzen.

[\[1\]](#_ftnref1) <https://openjdk.org/jeps/440>

Kategorien: [Insel](https://tutego.de/blog/javainsel/category/insel/), [Java 21](https://tutego.de/blog/javainsel/category/java-21/)

[← Alle Beiträge](https://tutego.de/blog/javainsel/)

---

## Navigation

- Previous: [Inselupdate: Pattern-Matching bei switch in Java 21](https://tutego.de/blog/javainsel/2023/08/pattern-matching-bei-switch-in-java-21.md)
- Next: [Inselupdate: Records implementieren Schnittstellen](https://tutego.de/blog/javainsel/2023/08/inselupdate-records-implementieren-schnittstellen.md)
