Ahoi, Java 13!

Java 13: Alle Features der neuen Version im Detail

Falk Sippach

© Shutterstock / Surawit K. Sakul

Wie schnell so ein Jahr vergangen ist, sieht man auch daran, dass Java schon wieder um zwei Versionsnummern gewachsen ist. Mittlerweile sollten wir Java-Entwickler uns ja an die kurzen Releasezyklen gewöhnt haben. Immerhin können wir jetzt regelmäßig neue Funktionen ausprobieren und werden nicht alle paar Jahre von einem riesigen Funktionsumfang neuer Features erschlagen. In diesem Artikel werfen wir einen Blick auf das gerade veröffentlichte Java 13.

In das JDK 13 haben es die folgenden Java Enhancement Proposals geschafft [1]:

  • JEP 350: Dynamic CDS Archives
  • JEP 351: ZGC: Uncommit Unused Memory
  • JEP 353: Reimplement the Legacy Socket API
  • JEP 354: Switch Expressions (Preview)
  • JEP 355: Text Blocks (Preview)

Auf den ersten Blick sieht es nicht nach viel aus. Tatsächlich kann man durch die Kürze der Zeit seit der Veröffentlichung von Java 12 aber auch nicht allzu viele Änderungen erwarten. Vielmehr sind die Releases zwischen den Long-Term-Support-(LTS-)Versionen meist dazu da, gewisse Features als Previews anzubieten, um frühzeitig Feedback von den Nutzern einzuholen. Die Funktionen werden dabei in den JEPs implementiert und – sobald sie eine gewisse Reife erreicht haben – mit dem nächsten Release des festgelegten halbjährlichen Zyklus ausgeliefert. Dadurch kann man nie genau vorhersagen, wie viele neue und vor allem für den normalen Java-Programmierer relevante Funktionen im nächsten Release enthalten sind. Das Ziel ist, die Preview-Features bis zur nächsten LTS-Version zu finalisieren, damit sie stabil genug ist und für die nächsten drei Jahre gut dasteht. Im September 2021 wird dann Java 17 das Erbe von Java 8 und 11 antreten.

Anpassungen an Switch Expressions

Wenn man die oben aufgeführte Featureliste durchschaut, sind aus Entwicklersicht hauptsächlich die beiden letzten Punkte interessant. So wurden beispielsweise die in Java 12 als Preview eingeführten Switch Expressions aufgrund des Userfeedbacks erweitert. Die Switch Expression ist eine Alternative zum umständlichen und fehlerträchtigen Switch Statement. Eine ausführliche Übersicht über die Verwendung findet sich in diversen Artikeln zu Java 12 [2].

Die größte Änderung in Java 13 ist das Ersetzen des Schlüsselworts break in der Switch Expression durch yield. Der Hintergrund ist die bessere Unterscheidbarkeit zwischen Switch-Statement (mit möglichem break) und den Expressions (mit yield). Mit der yield-Anweisung verlässt man den Switch und bekommt ähnlich wie bei einem return das Ergebnis des aktuellen Zweigs zurückgeliefert.

In Listing 1 folgt ein Codebeispiel. Oben sehen wir ein Statement mit break und Fall-Through. Im direkten Vergleich folgt eine Switch Expression mit dem neuen Schlüsselwort yield und Mehrfachlabeln. Im Gegensatz zur ersten Variante wird dort keine Variable verändert, sondern direkt das Ergebnis des case-Zweigs zurückgeliefert.

// Switch-Statement mit break
private static String statementBreak(int switchArg){
  String str = "not set";
  switch (switchArg){
    case 1:
    case 2:
      str = "one or two";
      break;
    case 3:
      str = "three";
      break;
  };
  return str;
}

// Switch-Expression mit yield
private static String expressionBreakWithValue(int switchArg){
  return switch (switchArg){
    case 1, 2: yield "one or two";
    case 3: yield "three";
    default: yield "smaller than one or bigger than three";
  };
}

Die in Java 12 eingeführte Arrow-Syntax funktioniert übrigens weiterhin (Listing 2).

private static String expressionWithArrow(int i) {
  return switch (i) {
    case 1, 2 -> "one or two";
    case 3 -> "three";
    default -> "smaller than one or more than three";
  };
} 

Die Switch Expressions bleiben vorerst noch im Preview-Modus, somit könnte es in den nächsten Java-Versionen weitere Anpassungen geben. Beim Kompilieren unter JDK 13 müssen darum die entsprechenden Flags angegeben werden:

javac --release 13 --enable-preview Examples.java  

Beim Starten muss das Preview-Feature ebenfalls aktiviert werden. Die Build-Tools (Maven etc.) bringen natürlich auch entsprechende Konfigurationsschalter mit:

java --enable-preview Examples

Text Blocks statt Raw String Literals

Text Blocks sind eigentlich nur ein kleiner Teil der ursprünglich bereits für Java 12 geplanten Raw String Literals (JEP 326). Die erste Implementierung der Raw String Literals war noch nicht bis ins letzte Detail durchdacht, das Feedback der Nutzer hatte viele Fragen aufgeworfen. Die genauen Details kann man in der Mailingliste [3] nachlesen. Mit Java 13 kommen nun erst einmal „nur“ die mehrzeiligen Textblöcke.

Das ist aber immerhin besser als nichts. Schließlich werden in vielen Java-Anwendungen Codeschnipsel aus anderen Sprachen wie HTML oder SQL verarbeitet, die der Übersichtlichkeit halber meist aus mehreren Zeilen bestehen. Bisher kann man solche Strings nur sehr umständlich definieren, wodurch die Lesbarkeit leidet. Für Zeilenumbrüche müssen beispielsweise extra Steuerbefehle (Escapen mit \n) eingesetzt werden. Andere Sprachen wie Groovy, Scala oder Kotlin bieten bereits sehr lange die Möglichkeit, mehrzeilige Texte zu definieren.

Die neuen Textblöcke verwenden dreifache Anführungsstriche als Begrenzungszeichen und können übrigens überall benutzt werden, wo auch normale Strings erlaubt sind. Listing 3 zeigt die Unterschiede zwischen traditioneller und neuer Syntax Die öffnenden müssen dabei im Gegensatz zu den schließenden dreifachen Anführungszeichen in einer eigenen Zeile stehen. Nichtsdestotrotz beginnt der eigentliche Inhalt erst mit der zweiten Zeile. Das erhöht die Lesbarkeit des Quellcodes, da so die Einrückung der ersten Zeile korrekt im Quelltext dargestellt wird.

// Ohne Text Blocks
String html = "\n" +
              "    \n" +
              "      

Hello, Escapes

\n" + " \n" + "\n"; // Mit Text Blocks String html = """

Hello, Text Blocks

""";

Weitere Beispiele finden sich im Artikel von Tim Zöller, der sich konkret mit dem JEP 355 befasst. Die Textblöcke werden übrigens bereits zur Compile-Zeit durch normale Strings ersetzt. Im Bytecode kann man dann nicht mehr sehen, wie der String ursprünglich definiert wurde.

Textblöcke in Java 13: Warum sich das lange Warten gelohnt hat

Dynamic CDS Archives

Neben den für Entwickler offensichtlichen Neuerungen ist auch wieder einiges unter der Haube der JVM und in der Klassenbibliothek passiert. Bereits in Java 5 wurde Class Data Sharing (CDS) eingeführt. Das Ziel von CDS ist die Verkürzung der Startzeiten von Java-Anwendungen, indem bestimmte Informationen über Klassen in sogenannten Class-Data-Sharing-Archiven abgelegt werden. Diese Daten können dann zur Laufzeit geladen und auch von mehreren JVMs benutzt werden. Bis Java 10 waren die geteilten Archive jedoch nur für den Bootstrap Class Loader zugänglich. Ab Java 10 wurde CDS um Application Class Data Sharing (AppCDS) erweitert. AppCDS ermöglicht dem eingebauten System- und Platform Class Loader sowie benutzerdefinierten Class Loadern, auf die CDS-Archive zuzugreifen. Zum Anlegen der CDS-Archive werden Klassenlisten benötigt, um die zu ladenden Klassen identifizieren zu können. Bisher mussten diese Klassenlisten durch Probeläufe der Anwendung ermittelt werden, um festzustellen, welche Klassen während der Ausführung tatsächlich geladen werden. Seit Java 12 werden Default-CDS-Archives standardmäßig mit dem JDK ausgeliefert, die auf der Klassenliste des JDKs basieren.

Dynamic CDS Archives bauen nun darauf auf. Ziel ist es, sich die zusätzlichen Probeläufe der Anwendung zu sparen. Nach der Ausführung einer Anwendung werden nur noch die neu geladenen Anwendungs- und Bibliotheksklassen archiviert, die nicht bereits im Default/Base Layer CDS enthalten sind. Aktiviert wird das dynamische Archivieren mit Kommandozeilenbefehlen. In einer zukünftigen Erweiterung könnte das Archivieren der Klassen dann vollständig automatisch und transparent ablaufen.

ZGC gibt ungenutzten Speicher frei

Heutzutage ist es nicht ungewöhnlich, dass Anwendungen viele tausend Benutzer gleichzeitig bedienen müssen. Diese Applikationen brauchen sehr viel Speicher, die Verwaltung des Speichers ist nicht trivial und hat Auswirkungen auf die Performance der Anwendung. Um diesen Anforderungen gerecht zu werden, hat Oracle in Java 11 den Z Garbage Collector (ZGC) eingeführt. Er verspricht sehr kurze Pausen beim Aufräumen von Heap-Speichern mit mehreren Terabytes. Bisher gab er den für die Anwendung reservierten Heap-Speicher aber nicht wieder frei. Das führte dazu, dass Anwendungen über ihre Lebensdauer hinweg für gewöhnlich weit mehr Speicher verbrauchen, als notwendig wäre. Besonders betroffen sind Anwendungen, die in ressourcenarmen Umgebungen ausgeführt werden. Andere Garbage Collectors wie der G1 und Shenandoah unterstützen bereits das Freigeben von ungenutztem Speicher.

Socket APIs erneuert

Die java.net.Socket– und java.net.ServerSocket-APIs und deren zugrunde liegende Implementierungen sind Überbleibsel aus dem JDK 1.0. Zu großen Teilen bestehen sie aus Legacy-Java- und C-Code. Das erschwert die Wart- und Erweiterbarkeit deutlich. Die NioSocketImpl soll die veraltete PlainSocketImpl nun ablösen. NioSocketImpl ist an die bereits vorhandene New I/O-Implementierung angelehnt und benutzt deren vorhandene Infrastruktur im JDK.
Die bisherige Implementierung ist zudem nicht kompatibel mit weiteren geplanten Erweiterungen der Sprache. Beispielsweise behindern Concurrency-Probleme den zukünftigen Einsatz der leichtgewichtigen User Threads (Fiber, Teil des Projects Loom).

Fazit

Die bisher beschriebenen Änderungen wurden in den JEPs (Java Enhancement Proposals) definiert. Es gibt aber noch weitere Anpassungen direkt in der Klassenbibliothek. Diese kann man sich entweder über den JDK API Diff Report Generator [4] oder den Java Almanac [5] visualisieren. Bei genauerem Hinschauen fällt auf, dass das alte Doclet API unter com.sun.javadoc entfernt wurde [6]. Außerdem wurden im Rahmen des JEP 355 (Text Blocks) der Klasse String drei neue Instanzmethoden hinzugefügt: formatted, stripIndent und translateEscapes.

Seit Java 10 können wir uns zweimal im Jahr (März und September) über neue Java-Releases freuen. Da natürlich in einem halben Jahr nicht so viel in der Entwicklung passieren kann, sind die jeweiligen Featurelisten zum Glück überschaubar. Die kurzen Updatezyklen ermöglichen es uns aber, regelmäßig in kurzen Abständen die Neuerungen auszuprobieren. Und das Java-Team bei Oracle bekommt so schnelleres und wertvolleres Feedback zu den neuen Funktionen, von denen sich ja einige über ein oder mehrere Releases im Preview-Status befinden. Auf dem Weg zur nächsten LTS-Version wird es durch Userfeedback dann gegebenenfalls noch Änderungen geben. So hatte man zum Beispiel auch im aktuellen LTS-Release Java 11 die in Java 9 und 10 angefangenen Arbeiten finalisiert.

Für den produktiven Einsatz seiner Java-Anwendungen kann man mittlerweile zwischen zwei Varianten wählen. Entweder man bleibt für drei Jahre beim aktuellen LTS-Release oder man aktualisiert zweimal im Jahr auf die jeweils für ein halbes Jahr von Oracle mit Updates versorgte Major-Version des OpenJDK. Letzteres darf man frei einsetzen, muss aber nach sechs Monaten auf die nächste Version updaten, um weiterhin Securityupdates und Patches zu erhalten. Bei der LTS-Variante gibt es sowohl kostenpflichtige Angebote (Oracle, Azul, …) als auch freie Installationen wie zum Beispiel von AdoptOpenJDK, Amazon Corretto, RedHat, SAP und Alibaba Dragonwell. Nach dem ersten Erstaunen über Oracles neue Lizenzpolitik gibt es jetzt eine Menge Alternativen, um Java in Produktion zu betreiben.

Zudem scheint Oracles Idee mit den halbjährlichen Major-Releases und damit regelmäßigen, wenn auch kleinen Updates aufzugehen. Bisher wurden die Versionen wie angekündigt pünktlich geliefert, und so können wir bereits auf die nächsten Neuerungen gespannt sein. Zunächst gilt es aber, das JDK 13 zu installieren [7] und die neuen Features auszuprobieren. Parallel laufen bereits die Arbeiten an der Version 14 [8]. Zum Zeitpunkt der Entstehung dieses Artikels war bereits der JEP 352 (Non-Volatile Mapped Byte Buffers) eingeplant. Zudem werden gegebenenfalls die Previews von Switch Expressions und Text Blocks finalisiert. Außerdem könnte im Rahmen des JEP 343 ein neues Tool zum Verpacken von in sich abgeschlossenen Java-Anwendungen in Erscheinung treten. Aber so ungewiss diese Änderungen zum jetzigen Zeitpunkt erscheinen, so schnell ist das nächste Release bereits unterwegs. Denn im März 2020 heißt ein weiteres Mal: „Alle halben Jahre wieder …“

Java 13 ist da – die Highlights in der Übersicht [mit Infografik]

Geschrieben von
Falk Sippach
Falk Sippach
Falk Sippach hat über 20 Jahre Erfahrung mit Java und ist bei der Mannheimer Firma OIO Orientation in Objects GmbH als Trainer, Software-Entwickler und Projektleiter tätig.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
4000
  Subscribe  
Benachrichtige mich zu: