Über unsMediaKontaktImpressum
Michael Inden 28. September 2021

JAVA 17 – Lieblingsfeatures

Java 17 hat vor ein paar Tagen das Licht der Welt erblickt und konsolidiert damit diverse, teils sehr interessante Features der halbjährlichen Releases in Form eines LTS-Release (Long Term Support). Wir stellen in diesem Artikel die Highlights vor.

Überblick über die wichtigsten Neuerungen

Folgende Aufzählung nennt wesentliche und im Anschluss einzeln thematisierte Neuerungen der letzten Java-Versionen inklusive des zugehörigen JEP (Java Enhancement Proposals):

  • JEP 378: Mit Java 15 kamen die mehrzeiligen Strings – Text Blocks genannt – hinzu.
  • JEP 394: In Java 16 vereinfacht das Pattern Matching for instanceof if-Abfragen.
  • JEP 395: Die gewichtigere Neuerung in Java 16 sind jedoch die Records. Diese erleichtern die Definition von Datencontainerklassen.
  • JEP 406: Java 17 Preview: Als Preview gibt es nun auch bei switch ein Pattern Matching analog zu instanceof.

JEP 361: Switch Expressions

Mit Java 14 und den Switch Expressions wird die Formulierung von Fallunterscheidungen deutlich erleichtert und bietet eine intuitive Schreibweise. Neben dem offensichtlichen Pfeil statt des Doppelpunkts der früheren Syntax können nun auch mehrere Werte hinter dem case angegeben werden. Praktischerweise wird kein break mehr benötigt: Die hinter dem Pfeil notierten Anweisungen werden jeweils nur spezifisch für das case ausgeführt und es existiert bei dieser Syntax kein Fall Through. Außerdem kann das switch nun einen Wert zurückgeben, wodurch sich die Definition von Hilfsvariablen vermeiden lässt.

jshell> import java.time.*

jshell> DayOfWeek day = DayOfWeek.FRIDAY
day ==> FRIDAY

jshell> int numOfLetters = switch (day)
   ...> {
   ...>     case MONDAY, FRIDAY, SUNDAY -> 6;
   ...>     case TUESDAY                -> 7;
   ...>     case THURSDAY, SATURDAY     -> 8;
   ...>     case WEDNESDAY              -> 9;
   ...> };
   ...>
numOfLetters ==> 6

JEP 378: Text Blocks

Seit JDK 15 unterstützt Java auch die Angabe von mehrzeiligen Strings (auch Text Blocks genannt). Zuvor war dies mühselig und aufwändig, da sämtliche Zeilentrenner sowie gegebenenfalls Anführungszeichen zu escapen waren. Mehrzeilige Strings bieten hier Abhilfe und werden durch drei Anführungszeichen eingeleitet und abgeschlossen:

jshell> String multiLineString = """
   ...> This is line 1
   ...> Second line with "quotes"
   ...> Last line with 'single quotes'
   ...> """
multiLineString ==> "This is line 1\nSecond line with \"quotes\"\nLast line with 'single quotes'\n"

Nach der mehrzeiligen Definition kann man wie zuvor gezeigt auf dem String agieren, also dessen Länge bestimmen, Bausteine ersetzen usw. Das liegt daran, dass ein solcher mehrzeiliger String vom Typ String ist:

jshell> multiLineString.getClass()
$2 ==> class java.lang.String

Somit werden alle dessen Methoden unterstützt.

Weitere Einsatzmöglichkeiten

Immer dann, wenn man nur kleinste fix definierte Informationen oder Datenbestände als JSON ausdrücken möchte, bieten sich Text Blocks an. Genauso kann man diese für HTML-Schnipsel oder aber SQL-Fragmente nutzen.

JEP 394: Pattern Matching bei instanceof

Bei instanceof gibt es in Form von Pattern Matching seit Java 16 eine hilfreiche Erweiterung, die es erlaubt, den Source-Code klarer zu gestalten. Schauen wir kurz zurück: Bislang sieht man immer wieder nach der Typprüfung eine Definition einer Hilfsvariablen inklusive eines Casts etwa wie folgt:

if (obj instanceof Person)
{
    final Person person = (Person) obj;
    // ... Zugriff auf person...
}

Das ist nötig, um mit der Variablen sinnvoll und typspezifisch weiterarbeiten zu können. Seit Java 16 kann man das Ganze folgendermaßen präziser und kürzer schreiben, indem man nach dem Typ bei instanceof eine sogenannte Binding-Variable angibt, auf die man dann im Block darunter typisierten Zugriff hat:

if (obj instanceof Person person)
{
    // Hier kann man auf die Variable person direkt zugreifen
}
else
{
    // Hier kein Zugriff auf person
    System.out.println(obj.getClass());
}

Obwohl das gerade Gezeigte schon recht nett ist, geht es noch ein wenig besser.
Man kann nämlich auf die Variable bereits im if-Ausdruck zugreifen:

if (obj instanceof String str && str.length() > 5)
{
    System.out.println("Länge: " + str.length());
}

JEP 395: Records

Java 16 bietet Records als simplifizierte Form von Klassen, deren Methoden sich implizit aus den als Konstruktorparametern definierten Attributen ergeben. Ein Record stellt damit eine Sammlung von Daten dar und modelliert nur genau einen unveränderlichen Zustand. Darüber hinaus werden automatisch Implementierungen von Methoden zum lesenden Attributzugriff sowie ein Konstruktor, toString() und equals() als auch hashCode() erzeugt. Damit sind Records in diversen Anwendungsfällen gewinnbringend einsetzbar, etwa für Methoden, die mehrere Werte zurückgeben sollen, Data Transfer Objects (DTOs) usw.

Beispiel

Schauen wir nach den einführenden Erklärungen für ein besseres Verständnis auf den folgenden Source-Code, der die Definition eines Records mit zwei Attributen x und y zeigt:

record MyPoint(int x, int y) { }

Betrachten wir einmal, wie viel Source-Code man schreiben müsste, um eine äquivalente Funktionalität mit den konventionellen Java-Sprachmitteln zu erreichen:

public final class MyPoint
{
    private final int x;
    private final int y;

    public MyPoint(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        
        MyPoint point = (MyPoint) o;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(x, y);
    }

    @Override public String toString()
    {
        return "MyPoint[x=" + x + ", y=" + y + "]";
    }
    
    // lesende Zugriffsmethoden auf x und y
}

Es lassen sich weitere Container erzeugen, die beispielsweise zur Parameterübergabe, als kombinierter Schlüssel (Compound Key) beim Zugriff auf Maps oder als Rückgabe genutzt werden können, beispielsweise folgende:

record ColorAndRgbDTO(String name, int red, int green, int blue) { }
record IntStringReturnValue(int code, String info) { }
record PizzaTop3Favorites(String top1, String top2, String top3) { }
record SimplePerson(String firstname, String lastname, LocalDate birthday) { }

JEP 406: Pattern Matching bei Switch (Preview)

Mit Java 16 wurde Pattern Matching für instanceof eingeführt und zuvor schon als nützlich beschrieben, weil sich lästige Casts sparen lassen. Diese Syntax-Neuerung ist nun auch für switch möglich und erlaubt noch verständlichere switch-Abfragen. Allerdings ist das Ganze zunächst in Java 17 in Form von Preview Features umgesetzt und zum Nachvollziehen müssen Sie diese geeignet aktivieren, etwa wie folgt in der JShell (und natürlich ein passendes JDK 17 installiert haben):

$ jshell --enable-preview
|  Welcome to JShell -- Version 17-ea
|  For an introduction type: /help intro

Beispiel

Nehmen wir an, wir müssten eine generische Methode zum Formatieren von Werten schreiben. Sofern wir Java 16 nutzen, können wir dies mithilfe von Pattern Matching und instanceof einigermaßen lesbar schreiben. Noch gefälliger wird das Ganze mit den
Switch Expressions in Kombination mit dem neu in Java 17 hinzugekommenen Pattern Matching:

static String formatterJava17PatternSwitch(Object obj) {
    return switch (obj) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> obj.toString();
    };
}

Praktische Besonderheiten: Weitere Abfragen im case / Unterstützung von null

Bislang war es nicht möglich, in den cases eines switchs den Wert null zu behandeln. Mit Java 17 und aktivierten Preview Features können wir nun auch null-Werte angeben. Analog zu instanceof sind in den cases nun auch Abfragen wie die folgenden möglich:

static void processData(Object obj) {
    switch (obj) {
        case null -> System.out.println("null is now allowed");
        case String str && str.startsWith("V1") ->              System.out.println("Processing V1");
        case String str && str.startsWith("V2") ->              System.out.println("Processing V2");
        case Integer i && i > 10 && i < 100 ->              System.out.println("Processing ints");
        default -> throw new IllegalArgumentException("invalid input");
    }
}

Fazit

Die Java-Versionen bis zur aktuellen 17 LTS enthalten eine Vielzahl sinnvoller und praktischer Neuerungen und Ergänzungen. Weil sich viele alltägliche Programmieraufgaben nun noch ein wenig eleganter und kürzer als noch mit den Vorgänger-LTS-Versionen Java 8 oder 11 realisieren lassen, sollte Java auch für die Zukunft für Entwickler und Firmen attraktiv bleiben. Insgesamt bildet die neue Java-LTS-Version einen würdigen Nachfolger von Java 11.

In diesem Artikel konnte ich dies nur überblicksartig darstellen und möchte Sie für eine fundierten Einstieg auf meine Bücher "Java – die Neuerungen in Version 9 bis 14" und "Der Weg zum Java-Profi" verweisen.

Autor
Das könnte Sie auch interessieren
Kommentare (2)
  • Peter Schuster
    am
    Sehr geehrter Herr Inden! Ich habe Ihr Buch "Java 8 - Die Neuerungen" sehr gern gelesen und warte gespannt, ob es ein "Java - Die Neuerungen von 9 bis 17" geben wird. Mit freundlichen Grüßen!
    • Michael Inden
      am
      Hallo Herr Schuster,

      besten Dank für die positive Rückmeldung. Die Neuerungen in Java 17 sind oft auch schon in früheren Java-Versionen als Preview inkludiert. Somit können Sie zwischenzeitlich für eine genauere Beschreibung auf meine Bücher "Java – die Neuerungen in Version 9 bis 14" (für Java 14) und "Der Weg zum Java-Profi" (für Java 15) zurückgreifen. Dort sind die wesentlichen Neuerungen wie Text Blocks, instanceof und Records beschrieben.

      Zu Ihrer konkreten Frage: Es gibt zwar Überlegungen für ein solches Buch, aber es ist noch nicht direkt geplant. Das könnte sich aber demnächst durchaus ändern.

      Beste Grüße
      Michael Inden

Neuen Kommentar schreiben