Dopo sei mesi di sviluppo, Oracle ha rilasciato la piattaforma Java SE 22 (Java Platform, Standard Edition 22), della quale viene utilizzato il progetto open source OpenJDK come riferimento. A parte la rimozione di alcune funzionalità obsolete, Java SE 22 mantiene la compatibilità con le versioni precedenti della piattaforma Java: la maggior parte dei progetti Java precedentemente scritti funzionerà senza modifiche sotto la nuova versione. Le versioni pronte per l'installazione di Java SE 22 (JDK, JRE e Server JRE) sono disponibili per Linux (x86_64, AArch64), Windows (x86_64) e macOS (x86_64, AArch64). La versione di riferimento di Java 22, sviluppata nell'ambito del progetto OpenJDK, è completamente open source sotto la licenza GPLv2 con eccezioni GNU ClassPath che consentono il collegamento dinamico a prodotti commerciali.
Java SE 22 è classificato come un rilascio con un ciclo di vita di supporto normale, con aggiornamenti rilasciati fino al prossimo rilascio. Per un ramo a lungo termine (LTS), si consiglia di utilizzare Java SE 21 o Java SE 17, con aggiornamenti forniti fino al 2031 e al 2029 rispettivamente (pubblici fino al 2028 e 2026). Il supporto pubblico del ramo LTS Java SE 11 è terminato a settembre dello scorso anno, ma il supporto esteso continuerà fino al 2032. Il supporto esteso per il ramo LTS Java SE 8 durerà fino al 2030.
Ricordiamo che a partire dal rilascio di Java 10, è stato introdotto un nuovo processo di sviluppo che prevede cicli più brevi per la creazione di nuovi rilasci. Le nuove funzionalità vengono ora sviluppate in un ramo master costantemente aggiornato, in cui vengono integrate modifiche pronte e dal quale si diramano rami per la stabilizzazione di nuovi rilasci ogni sei mesi.
Tra le novità di Java 22 si possono notare:
- Nel garbage collector G1 è stata implementata la supporto al pinning delle regioni (region pinning), consentendo di bloccare temporaneamente la posizione degli oggetti Java in memoria per evitare il loro spostamento da parte del garbage collector e garantire una trasmissione sicura dei riferimenti a questi oggetti tra Java e il codice nativo. Il pinning consente di ridurre le latenze ed evitare di disabilitare il garbage collection durante l'esecuzione di sezioni critiche (critical regions) JNI (Java Native Interface) con codice nativo (durante l'esecuzione di queste sezioni, la JVM non deve spostare gli oggetti critici associati per prevenire condizioni di race). Il pinning tiene gli oggetti critici al di fuori della vista del garbage collector, che può continuare a pulire le aree non ancorate.
- È stata aggiunta una nuova funzionalità che consente di specificare espressioni nei costruttori prima della chiamata a super(...), utilizzata per chiamare esplicitamente il costruttore della classe genitore dal costruttore della classe derivata, purché tali espressioni non facciano riferimento all'istanza creata dal costruttore. class Outer { void hello() { System.out.println("Hello"); } class Inner { Inner() { hello(); super(); } } }
- È stato stabilizzato l'API FFM (Foreign Function & Memory), che consente l'interazione tra programmi Java e codice e dati esterni attraverso la chiamata di funzioni da librerie esterne e accesso alla memoria al di fuori della JVM, senza ricorrere all'uso di JNI (Java Native Interface).
- È stata inclusa la supporto per variabili anonime e pattern matching: invece di utilizzare variabili e pattern non utilizzati ma necessari durante le chiamate, ora è possibile indicare il simbolo "_". // era String pageName = switch (page) { case GitHubIssuePage(var url, var content, var links, int issueNumber) -> "ISSUE #" + issueNumber; ... }; // ora è possibile String pageName = switch (page) { case GitHubIssuePage(_, _, _, int issueNumber) -> "ISSUE #" + issueNumber; };
- È stata proposta una implementazione preliminare dell'API Class-File per l'analisi, la generazione e la trasformazione dei file di classi Java. 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); } } });
- Nell'utilità java è stata implementata la possibilità di avviare programmi Java forniti sotto forma di più file di codice o librerie di classi precompilate, senza la necessità di compilare separatamente questi file e senza configurare un sistema di build. Questa nuova funzionalità semplifica l'avvio di programmi in cui il codice di diverse classi è separato in file distinti. Prog.java: class Prog { public static void main(String[] args) { Helper.run(); } } Helper.java: class Helper { static void run() { System.out.println("Hello!"); } }
Ad esempio, per avviare un programma composto da due file "Prog.java" e "Helper.java", ora è sufficiente eseguire "java Prog.java", il che porterà alla compilazione della classe Prog, alla definizione di un riferimento alla classe Helper, alla ricerca e compilazione del file Helper.java e alla chiamata del metodo main.
- È stata aggiunta una seconda implementazione preliminare dei modelli di stringa (String Template), implementati in aggiunta ai letterali di stringa e ai blocchi di testo. I modelli di stringa consentono di combinare testo con espressioni e variabili calcolate senza utilizzare l'operatore «+». La sostituzione delle espressioni avviene tramite sostituzioni \{..}, con la possibilità di collegare gestori speciali per verificare la correttezza dei valori sostituiti. Ad esempio, un gestore SQL verifica i valori sostituiti nel codice SQL e restituisce un oggetto java.sql.Statement, mentre un gestore JSON monitora la correttezza delle sostituzioni JSON e restituisce JsonNode. String query = «SELECT * FROM Person p WHERE p.» + property + » = ‘» + value + «‘»; // era Statement query = SQL.»»»SELECT * FROM Person p WHERE p.\{property} = ‘\{value}'»»»; // è adesso
- È stata aggiunta una settima implementazione preliminare dell'API Vector, che fornisce funzioni per calcoli vettoriali eseguiti utilizzando istruzioni vettoriali dei processori x86_64 e AArch64 e consente di applicare operazioni simultaneamente a più valori (SIMD). A differenza delle capacità di vettorizzazione automatica delle operazioni scalari fornite dal compilatore JIT HotSpot, la nuova API consente di gestire esplicitamente la vettorizzazione per l'elaborazione parallela dei dati.
- È stata aggiunta un'implementazione preliminare estesa dell'API Stream, che supporta la definizione di operazioni intermedie personalizzate, utili nei casi in cui le operazioni intermedie integrate non siano sufficienti per la trasformazione dei dati desiderata. I gestori personalizzati vengono collegati tramite una nuova operazione intermedia Stream::gather(Gatherer), che elabora gli elementi dello stream applicando il gestore fornito dall'utente. 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]]
- È stato proposto per il test una seconda variante dell'API sperimentale per la concorrenza strutturata (Structured Concurrency), che semplifica lo sviluppo di applicazioni multithread gestendo più attività eseguite in thread diversi come un'unica unità.
- È stata aggiunta una seconda implementazione preliminare di classi dichiarate implicitamente e istanze anonime del metodo «main», in cui è possibile fare a meno delle dichiarazioni public/static, della passaggio di un array di argomenti e di altre entità associate alla dichiarazione di classi. // era public class HelloWorld { public static void main(String[] args) { System.out.println(«Hello world!»); } } // ora è possibile void main() { System.out.println(«Hello, World!»); }
- È stata aggiunta una seconda implementazione preliminare di valori limitati (Scoped Values), che consentono la condivisione di dati immutabili tra i thread e uno scambio efficace di dati tra i thread secondari (i valori sono ereditati). I valori limitati sono stati sviluppati per sostituire il meccanismo delle variabili locali ai thread (thread-local variables) e sono più efficienti nell'uso di un numero molto elevato di thread virtuali (migliaia e milioni di thread). La principale differenza tra i valori limitati e le variabili locali ai thread è che i primi vengono scritti una sola volta, non possono essere modificati in seguito e rimangono accessibili solo durante l'esecuzione del thread.
- Nel garbage collector Parallel è stata migliorata l'efficienza nella gestione di grandi array di oggetti. L'ottimizzazione ha consentito di ridurre in alcuni test con grandi array di oggetti il ritardo prima dell'inizio della ricerca di un oggetto del 20%.
Inoltre, si segnala la pubblicazione di un aggiornamento della piattaforma per la creazione di applicazioni con interfaccia grafica JavaFX 22.
Fonte: opennet.ru
