Neues in Java 13

Java-Release 13 ist für September 2019 geplant. Es ist bereits das dritte Major-Release nach der Bekanntgabe des neuen Lizenzmodells und Release-Zyklus im September 2018. Einige Features sind vielversprechend. Für Entwickler halten sich die neuen Features jedoch in Grenzen.

Zu den Neuigkeiten von Java 13 gehören 5 Features, welche in Form von JDK-Enhancement-Proposal (JEP) beschrieben sind. Die meisten Änderungen des Releases betreffen interne Optimierungen und Refactorings. Die für Softwareentwickler sichtbaren Features – und davon gibt es zwei – sind in diesem Artikel als erste beschrieben. Java 13 gehört nicht zu den sogenannten LTS-Releases (Long-Term-Support) und wird bereits im März 2020 von JDK 14 abgelöst.

JEP 354: Switch-Expressions (Preview)

Bei JEP 354 handelt sich dabei um eine Erweiterung  von JEP 325 (Switch-Expressions), was als Preview-Language-Feature in JDK 12 erschienen ist. Die Änderung basiert auf dem Gavin Bierman’s Vorschlag, neue Form der break Anweisung mit einem Wert durch die yield Anweisung zu ersetzen.

Somit kann man leichter zwischen den Switch-Anweisungen und Switch-Ausdrücken unterscheiden:

  • Break-Anweisung wird in einer Switch-Anweisung, jedoch nicht im Switch-Ausdruck verwendet.
  • Das Ziel einer Yield-Anweisung kann ein Switch-Ausdruck, aber keine Switch-Anweisung sein.

JEP 355: Text-Blocks (Preview)

Das früher für JDK 13 geplante Feature-Raw-String-Literals (JEP 326) musste dem JEP 355 weichen. Dabei geht es um das Einführen von formatierten Textblöcken, wie in dem folgenden Beispiel:

Während dieses Feature in produktionsreifem Code eher weniger Verwendung findet, soll es die Entwicklung von Tests oder Prototypes spürbar erleichtern. Bei der Generierung von Bytecode werden die Textblöcke normalisiert und in normale Java-Strings umgewandelt. Zur Normalisierung gehört unter anderem:

  • Incidental-White-Spaces werden entfernt (in dem Beispiel als Punkte dargestellt)
  • Trailing-White-Spaces werden entfernt
  • Zeilenumbrüche werden unabhängig von der Plattform zu LF (auch bekannt als \n )

Die Interpretation von Escapes (wie z.B. \t oder \n) erfolgt nach der Normalisierung und funktioniert wie in herkömmlichen Strings. Die aus Kotlin oder Scala bekannten Variablenplatzhalter innerhalb des Blocks werden im Rahmen JEP 355 nicht unterstützt. Die Spezifikation verweist explizit auf zukünftige Implementierungen.

Beim Auswerten von Text-Blöcken werden aktuell nur die Einrückung mit Spaces unterstützt (Build 25 vom 14.06.2019). Die Incidental-Tabs werden ignoriert. Das neue Feature wird dadurch einen entscheidenden Einfluss im „Krieg Tabs versus Spaces” haben. Die Tabs innerhalb des Textes werden unverändert beibehalten und wie \t interpretiert.

JEP 350: Dynamic-CDS-Archives

Die erstmals in Java 5 erschienene Funktion Class-Data-Sharing erlaubte es, mehreren JVMs die einmal geladenen Classes mittels CDS-Archives zusammen zu nutzen. Die ursprünglich auf Bootstrap-Class-Loader beschränkte Funktion wurde zuletzt im JDK-Release 10 im Rahmen von JEP 310 auf den Application-Class-Loader ausgeweitet. Die neue verbesserte Version ist als AppCDS bekannt. Dies kam in der ersten Linie den Application-Servern zugute: Je nach Anwendungsfall sind laut JEP-Beschreibung deutliche Einsparungen beim RAM-Verbrauch zu verzeichnen. Die Startup-Zeiten verbesserten sich zum Teil um bis zu 30 Prozent. Das Benutzen des AppCDS blieb aufwendig. Im Grunde musste man die Liste von archivierten Klassen manuell erzeugen und pflegen. Im Rahmen von JEP 350 wurde AppCDS nochmal erweitert und deren Nutzung vereinfacht. Anstatt wie bis jetzt in mehreren Programmprobeläufen eine Klassenliste manuell zu erzeugen und danach das Archive (mit der Option -Xshare:dump) zu erstellen, werden alle geladenen Klassen und Bibliothekklassen am Programmende dynamisch zu einem Archiv hinzugefügt, soweit diese nicht im Base-Layer CDS-Archiv enthalten sind. Eine nachträgliche Erweiterung dieses JEP könnte eine automatische Archivgenerierung beim ersten Lauf einer Anwendung durchführen. Die Nutzung von CDS/AppCDS könnte dann völlig transparent und automatisch erfolgen. Aktiviert wird das Feature mit der Option XX:ArchiveClassesAtExit=<filename>. Das erzeugte Archiv kann dann mit der Option XX:SharedArchiveFile=<filename> verwendet werden:
% java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello

Verwendung des Archives in der gleichen Anwendung:
% java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello

 

JEP 351: ZGC – Uncommit unused Memory

In Java 11 wurde der neue Z Garbage-Collector ( ZGC) eingeführt, der sich aktuell noch in der Entwicklung befindet. Der neue Garbage-Collector ist sehr vielversprechend, da er eine höhere Geschwindigkeit bietet und niedrigere CPU-Auslastung für großen Heap (>16Gb) ermöglicht. Im Moment steht ZGC nur für 64-Bit Linux-Plattformen zur Verfügung.

Im Gegensatz zu anderen Garbage-Collectoren wie G1 oder Shenandoah kann ZGC bislang keinen Heap-Speicher an das Betriebssystem zurückgeben, auch dann nicht, wenn dieser längere Zeit nicht mehr verwendet wird. ZGC-Heap besteht aus Heap-Regionen, die als ZPages bezeichnet werden. Jede Region ist mit einem bestimmten Teil des Speichers in einer variablen Größe verknüpft. Falls ZGC den Heap komprimiert, werden die freigegebenen ZPages in einen Cache (ZPageCache) abgelegt, um diese bei Bedarf schnell wieder verwenden zu können. Diese Vorgehensweise ist für die Programm-Performance entscheidend, da die Speicherzuweisung und -freigabe eine relativ teure Operation ist. Der Cache hält die ZPages nach der letzten Nutzung (least-recently-used) sowie nach der Größe klein, mittel und groß sortiert. Somit ist es relativ einfach, diese nach einer definierten Zeit aus dem Cache zu entfernen und den Speicher frei zu geben. Eine einfachere Möglichkeit wäre es, einen Timeout- oder Delay-Wert zu definieren, wie lange eine ZPage im Cache liegen darf, bevor diese aufgeräumt wird. Dieser Wert sollte einen vernünftigen Default-Wert besitzen und bei Bedarf überschreibbar sein. Eine Alternative dazu könnte eine komplexeres Verfahren sein, das anhand von GZ-Frequenz und anderen Daten einen geeigneten Timeout-Wert ermittelt und anwendet. Welche der beiden Optionen zum Einsatz kommen wird, ist zum jetzigen Zeitpunkt noch nicht bekannt. Es ist denkbar, dass zuerst eine konfigurierbare Variante (-XX:ZUncommitDelay=<seconds>) veröffentlicht wird und die komplexere Version später nachgeliefert wird. Die Uncommit-Funktion ist per Default aktiv, kann aber mit -XX:-ZUncommit explizit deaktiviert werden.

JEP 353: Reimplement the Legacy Socket-API

Diese Änderung enthält umfangreiches Refactoring und Neuimplementierung der Java-Socket- und ServerSocket-API. Der Code wurde mithilfe von NIO-Bibliotheken grundlegend überarbeitet. Fehlerbehandlung und Garbage-Collector-Funktionalität wurden verbessert. In erster Linie handelt es sich hierbei vielmehr eine interne Änderung, welche die zukünftige Entwicklung des JDK erleichtern soll. Eine der wichtigsten Motivationen dieses Projektes ist ein weiterer Schritt hin zu einem leichtgewichtigen, kooperativen Ausführungsmodell des Projektes Loom[5]. Ältere Entwickler werden sich dabei vielleicht noch an Cooperative-Multitasking von Windows 3.1 erinnern. Die Umgebung, in unserem Fall die JVM, übernimmt die Steuerung zwischen virtuellen Threads und nutzt dabei eine sehr viel kleinere Anzahl an echten System-Threads. Solche virtuellen Threads werden Fibers genannt. Beim Verwalten von Fibers muss die JVM in der Lage sein, den aktuell laufenden Code zu unterbrechen und zu einem anderen Code zu schalten. Dafür eignen sich vor allem

Dafür eignen sich vor allem Programmstellen, an denen die Anwendung ohnehin auf externe I/O Prozesse warten muss. Zwei Voraussetzungen sind für die Umsetzung unverzichtbar: Die eigentliche I/O-Kommunikation darf dabei nicht unterbrochen werden, sondern muss im Hintergrund weiterlaufen. Die I/O Kommunikation selbst sollte dabei nicht nativ programmiert, sondern ebenfalls in Java implementiert werden, da die JVM ansonsten keine Möglichkeiten hat, das Fiber anzuhalten.

Da die alte Socket-API im Blocking-Mode lief und zum größten Teil nativ programmiert wurde, war eine Änderung des JEP 353 für die Weiterentwicklung bitter nötig. Ansonsten befindet sich das Projekt Loom noch in einem frühen Entwicklungsstadium und ist für die meisten Entwickler nicht von Bedeutung. Das Java-Team verspricht die Änderungen für die häufigsten Use-Cases transparent zu gestalten. In Bezug auf Geschwindigkeit ist die neue Implementierung laut JEP-Beschreibung nur minimal besser: etwa 0 bis 3 Prozent. Aus Kompatibilitätsgründen wird es noch eine Weile möglich sein die alte Implementierung von Sockets zu nutzen. Die Steuerung erfolgt wie gewohnt über die -D Parameter.

Rodion Alukhanov ist Senior-Software-Entwickler bei ip.labs GmbH mit Sitz in Bonn. Seine mehrjährige Erfahrung streckt sich von MS-DOS über die Hausautomation bis in die AWS-Cloud. Seine Schwerpunkte sind Cloud-Migration, Big-Data und Integration-Tests.

Alexander Peters ist Senior-Software-Entwickler bei ip.labs GmbH mit Sitz in Bonn. Er hat mehr als zehn Jahre Berufserfahrung in der webbasierten Softwareentwicklung mit Java (EE) und Spring Framework. Seine Schwerpunkte liegen bei der serverseitigen Anwendungsentwicklung sowie bei der Definition und Implementierung von externen und internen Schnittstellen.

Markus Kett


Leave a Reply