Nach sechs Monaten Entwicklung hat Oracle die Java SE 22-Plattform (Java Platform, Standard Edition 22) veröffentlicht, wobei das offene Projekt OpenJDK als Referenzimplementierung dient. Abgesehen von der Entfernung einiger veralteter Funktionen bleibt die Rückwärtskompatibilität zu früheren Versionen der Java-Plattform in Java SE 22 bestehen – die meisten zuvor geschriebenen Java-Projekte werden ohne Änderungen auch mit der neuen Version lauffähig sein. Installationsbereite Builds von Java SE 22 (JDK, JRE und Server JRE) sind für Linux (x86_64, AArch64), Windows (x86_64) und macOS (x86_64, AArch64) verfügbar. Die im Rahmen des OpenJDK-Projekts entwickelte Referenzimplementierung von Java 22 ist vollständig unter der GPLv2-Lizenz mit Ausnahmen für GNU ClassPath veröffentlicht, die dynamisches Linking mit kommerziellen Produkten erlauben.
Java SE 22 wird als reguläre Release-Version eingestuft, für die Updates bis zur nächsten Veröffentlichung bereitgestellt werden. Für eine langfristige Unterstützung (LTS) sollten Sie auf Java SE 21 oder Java SE 17 zurückgreifen, deren Updates bis 2031 bzw. 2029 erscheinen werden (öffentlich bis 2028 und 2026). Die öffentliche Unterstützung des LTS-Zweigs von Java SE 11 endete im September letzten Jahres, jedoch wird die erweiterte Unterstützung bis 2032 bereitgestellt. Die erweiterte Unterstützung des LTS-Zweigs von Java SE 8 wird bis 2030 fortgesetzt.
Erinnern wir uns daran, dass mit der Veröffentlichung von Java 10 das Projekt auf einen neuen Entwicklungsprozess umgestiegen ist, der einen kürzeren Zyklus für die Erstellung neuer Releases umfasst. Neue Funktionen werden nun in einem ständig aktualisierten Master-Zweig entwickelt, in den fertige Änderungen integriert werden, von dem alle sechs Monate Stabilitätszweige für neue Releases abgezweigt werden.
Zu den Neuerungen in Java 22 zählen:
- Im G1 Garbage Collector ist die Unterstützung für das Festlegen von Regionen (Region Pinning) implementiert. Dies ermöglicht es, den Standort von Java-Objekten im Speicher vorübergehend zu fixieren, um zu verhindern, dass sie vom Garbage Collector verschoben werden. Dadurch wird eine sichere Übertragung von Referenzen auf diese Objekte zwischen Java und nativem Code gewährleistet. Das Festlegen reduziert Verzögerungen und macht es möglich, ohne Deaktivierung des Garbage Collectors kritische Abschnitte (Critical Regions) im JNI (Java Native Interface) mit nativem Code auszuführen. Während der Ausführung dieser Abschnitte darf die JVM die damit verbundenen kritischen Objekte nicht verschieben, um Wettlaufbedingungen zu vermeiden. Das Festlegen bringt kritische Objekte aus dem Blickfeld des Garbage Collectors, der weiterhin unfixierte Bereiche bereinigen kann.
- Eine vorläufige Möglichkeit wurde hinzugefügt, die es erlaubt, in Konstruktoren von Ausdrücken vor dem Aufruf von super(…) anzugeben, der verwendet wird, um den Konstruktor der übergeordneten Klasse aus dem Konstruktor der abgeleiteten Klasse explizit aufzurufen, vorausgesetzt, diese Ausdrücke beziehen sich nicht auf das durch den Konstruktor erstellte Exemplar. class Outer { void hello() { System.out.println("Hello"); } class Inner { Inner() { hello(); super(); } } }
- Die API FFM (Foreign Function & Memory) wurde stabilisiert, um die Interaktion von Java-Programmen mit externem Code und Daten über den Aufruf von Funktionen aus externen Bibliotheken und den Zugriff auf Speicher außerhalb der JVM zu ermöglichen, ohne auf JNI (Java Native Interface) zurückzugreifen.
- Die Unterstützung für anonyme Variablen und Pattern Matching wurde eingeführt – anstelle von ungenutzten, aber notwendigen Variablen und Mustern bei Aufrufen kann jetzt das Zeichen „_“ angegeben werden. // war String pageName = switch (page) { case GitHubIssuePage(var url, var content, var links, int issueNumber) -> "ISSUE #" + issueNumber; … }; // jetzt ist es möglich String pageName = switch (page) { case GitHubIssuePage(_, _, _, int issueNumber) -> "ISSUE #" + issueNumber; };
- Es wird eine vorläufige Implementierung der API Class-File zur Analyse, Erstellung und Transformation von Java-Klassen-Dateien vorgeschlagen. ClassFile cf = ClassFile.of(); ClassModel classModel = cf.parse(bytes); byte[] newBytes = cf.build(classModel.thisClass().asSymbol(), classBuilder -> { for (ClassElement ce : classModel) { if (!(ce instanceof MethodModel mm && mm.methodName().stringValue().startsWith("debug"))) { classBuilder.with(ce); } } });
- Das Utility java ermöglicht das Starten von Java-Programmen, die in Form mehrerer Code-Dateien oder vorcompilierter Klassenbibliotheken bereitgestellt werden, ohne dass eine separate Kompilierung dieser Dateien oder eine Konfiguration des Build-Systems erforderlich ist. Diese neue Funktion vereinfacht das Starten von Programmen, bei denen der Code verschiedener Klassen in separate Dateien ausgelagert ist. Prog.java: class Prog { public static void main(String[] args) { Helper.run(); } } Helper.java: class Helper { static void run() { System.out.println("Hello!"); } }
Zum Beispiel reicht es jetzt aus, um ein Programm zu starten, das aus den beiden Dateien „Prog.java“ und „Helper.java“ besteht, einfach „java Prog.java“ auszuführen. Dies führt zur Kompilierung der Klasse Prog, zum Erstellen der Referenz auf die Klasse Helper, zum Suchen und Kompilieren der Datei Helper.java und zum Aufrufen der Methode main.
- Die zweite Vorabversion der String-Templates wurde hinzugefügt. Diese Ergänzung zu den String-Literalen und Textblöcken ermöglicht es, Text mit berechneten Ausdrücken und Variablen zu kombinieren, ohne den Operator „+“ zu verwenden. Die Einfügung von Ausdrücken erfolgt durch Platzhalter \{..}, wobei spezielle Handler zur Überprüfung der eingefügten Werte genutzt werden können. Beispielsweise sorgt der SQL-Handler für die Überprüfung von Werten, die in SQL-Code eingefügt werden, und gibt ein Objekt java.sql.Statement zurück, während der JSON-Handler die Korrektheit der JSON-Platzhalter überwacht und JsonNode zurückgibt. String query = «SELECT * FROM Person p WHERE p.» + property + » = ‘» + value + «‘»; // war Statement query = SQL.»»»SELECT * FROM Person p WHERE p.\{property} = ‘\{value}'»»»; // ist
- Die siebte Vorabversion der Vector-API wurde hinzugefügt. Diese bietet Funktionen für Vektorberechnungen, die mit Vektorbefehlen von x86_64- und AArch64-Prozessoren durchgeführt werden und es ermöglichen, gleichzeitig Operationen auf mehreren Werten anzuwenden (SIMD). Im Gegensatz zu den Auto-Vektorisierungsfunktionen für skalare Operationen, die im HotSpot-JIT-Compiler bereitgestellt werden, bietet die neue API die Möglichkeit, die Vektorisierung für die parallele Datenverarbeitung explizit zu steuern.
- Die Vorabversion der erweiterten Stream-API wurde hinzugefügt, die die Definition eigener Zwischenoperationen unterstützt. Diese kann nützlich sein, wenn die vorhandenen eingebauten Zwischenoperationen für die gewünschte Datenumwandlung nicht ausreichen. Benutzerdefinierte Handler können über die neue Zwischenoperation Stream::gather(Gatherer) angeschlossen werden, die die Elemente des Streams verarbeitet und den benutzerdefinierten Handler anwendet. jshell> Stream.of(1,2,3,4,5,6,7,8,9).gather(new WindowFixed(3)).toList() $1 ==> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
- Die zweite Testversion der experimentellen API für strukturierten Parallelismus (Structured Concurrency) wurde vorgestellt. Sie vereinfacht die Entwicklung von Multithread-Anwendungen, indem sie mehrere Aufgaben, die in verschiedenen Threads ausgeführt werden, als eine Einheit behandelt.
- Die zweite Vorabimplementierung von implizit deklarierten Klassen und anonymen Instanzen der Methode „main“ wurde hinzugefügt. Dabei ist es möglich, ohne die Deklarationen von public/static, die Übergabe eines Argumentenarrays und andere mit der Klassendeklaration verbundene Entitäten auszukommen. // Vorher: public class HelloWorld { public static void main(String[] args) { System.out.println("Hello world!"); } } // Jetzt: void main() { System.out.println("Hello, World!"); }
- Die zweite Vorabversion der Scoped Values wurde hinzugefügt, die es ermöglichen, unveränderliche Daten in Streams gemeinsam zu nutzen und effizient zwischen untergeordneten Streams auszutauschen (Werte werden vererbt). Scoped Values sind entwickelt worden, um den Mechanismus der thread-lokalen Variablen zu ersetzen und sind effizienter beim Einsatz einer sehr großen Anzahl von virtuellen Threads (Tausende und Millionen von Threads). Der Hauptunterschied zwischen Scoped Values und thread-lokalen Variablen besteht darin, dass erstere einmal geschrieben werden, danach nicht mehr geändert werden können und nur während der Ausführung des Threads verfügbar bleiben.
- Der Garbage Collector Parallel hat die Leistung bei der Verarbeitung großer Objektmengen verbessert. Die Optimierung hat in einigen Tests mit großen Objektarrays die Verzögerung vor dem Beginn der Objektsuche um 20 % reduziert.
Zusätzlich kann die Veröffentlichung des Updates für die JavaFX-Plattform zur Erstellung von grafischen Benutzeroberflächen 22 hervorgehoben werden.
Quelle: opennet.ru
