Java 26 : Quoi de neuf?

Java 26 : Quoi de neuf?

Maintenant que Java 26 est features complete (Rampdown Phase Two au jour d’écriture de l’article), c’est le moment de faire le tour des fonctionnalités qu’apporte cette nouvelle version, à nous, les développeurs.

Cet article fait partie d’une suite d’article sur les nouveautés des dernières versions de Java, pour ceux qui voudraient les lire en voici les liens : Java 25, Java 24, Java 23, Java 22, Java 21, Java 20, Java 19, Java 18, Java 17, Java 16, Java 15, Java 14, Java 13, Java 12, Java 11Java 10, et Java 9.

Après Java 25 et ses 18 JEPs, Java 26 arrive avec un petit nombre de JEPs, 10, avec très peu de nouvelle fonctionnalités.

JEP 500: Prepare to Make Final Mean Final

Un champ final est censé ne jamais être modifié après son initialisation. Mais hélas, la réflexion profonde (deep reflection) permet de rendre accessible un champ final pour pouvoir ensuite le modifier via la méthode Field.setAccessible(true). Modifier un champs final casse l’intégrité de la JVM car cela contrevient à l’intention du développeur, avec tous les risques de sécurité que cela peut engendrer.

De plus, certaines optimisations de la JVM ne peuvent s’appliquer aux champs finaux tel que le constant folding du Just In Time compiler (JIT), une optimisation qui évalue une expression constante une seule fois plutôt que chaque fois qu’elle est utilisée.

Les records interdisent déjà la modification de champs finals.

La JEP 500 va émettre un warning dans les logs de la JVM la première fois qu’un champ final est modifié via réflexion profonde.

WARNING: Final field f in p.C has been [mutated/unreflected for mutation] by class com.foo.Bar.caller in module N (file:/path/to/foo.jar)
WARNING: Use --enable-final-field-mutation=N to avoid a warning
WARNING: Mutating final fields will be blocked in a future release unless final field mutation is enabled

Cela peut être contrôlé via l’option JVM --illegal-final-field-mutation qui peut prendre les valeurs :

  • allow : permet la modification de champ finaux.
  • warn : émet un warning dans les logs de la JVM la première fois qu’un champ final est modifié, c’est le comportement par défaut en Java 26.
  • debug : identique à warn mais va inclure en plus la stack trace.
  • deny : interdit la modification de champs finaux.

Une future release de Java passera le comportement par défaut à deny.

Il est possible de sélectivement autoriser la modification de champs finaux via l’option JVM --enable-final-field-mutation=M1,M2 qui prend en paramètre la liste des modules à autoriser.

Plus d’information dans la  JEP 500.

JEP 504: Remove the Applet API

Supprime l’API des applets qui avait été dépréciée pour suppression en Java 17.

Les naviguateurs actuel ne supportent de toute façon plus les applets depuis longtemps.

Plus d’information dans la  JEP 504.

JEP 516: Ahead-of-Time Object Caching with Any GC

La JEP 483: Ahead-of-Time Class Loading & Linking a introduit en Java 24 la possibilité de créer un cache AOT (Ahead of Time – avant le lancement de l’application) contenant les classes déjà chargées et liées d’une application pour améliorer son temps de démarrage.

Celui-ci a été enrichi en Java 25 avec les informations de profiling des méthodes via la JEP 515: Ahead-of-Time Method Profiling.

En Java 26, ce cache a été amélioré pour stocker les objets de manière agnostique au GC, permettant un support pour tous les GC, et surtout l’utilisation d’un cache AOT par une JVM utilisant un GC différent de celui utilisé lors de la création du cache.

Plus d’information dans la  JEP 516.

JEP 517: HTTP/3 for the HTTP Client API

La JEP 517 apporte le support d’HTTP/3 dans le client HTTP du JDK.

Le client HTTP du JDK utilise toujours HTTP/2 par défaut.

Pour utiliser HTTP/3 il faut sélectionner cette version lors de la création du client HTTP :

var client = HttpClient.newBuilder()
               .version(HttpClient.Version.HTTP_3)
               .build();

Plus d’information dans la  JEP 517.

JEP 522: G1 GC: Improve Throughput by Reducing Synchronization

G1 est le garbage collector (GC) par défaut, mais il est parfois moins performant que le ParallelGC car pour réaliser une partie de son travail de manière concurrente à l’application, il nécessite de partager les ressources CPU avec les threads applicatifs et de se coordoner avec eux.

la JEP 522 augmente à la fois le débit et la latence des applications en réduisant la quantité de synchronisation requise entre les threads d’application et les threads GC. Plus précisément la write barrier de G1 a été modifiée pour ne plus synchroniser sur la card table via l’ajout d’une seconde card table. Sans trop rentrer dans les détails, la write barrier est un bout de code appelé à chaque allocation d’un objet permettant à G1 de tracer les allocations sans arrêter les threads applicatif. Enlever cette synchronisation va réduire le coût de G1 à chaque écriture et donc améliorer le débit de l’application.

Plus d’information dans la  JEP 522.

UUIDv7 support

La nouvelle méthode UUID.ofEpochMillis(long) permet de créer un UUID type 7 (UUIDv7) depuis un timestamp Unix Epoch.

uuidv7

Les UUIDv7 sont créées en attribuant un timestamp Unix en millisecondes dans les 48 bits les plus significatifs, en attribuant la version requise (4 bits) et la variante (2 bits) et en remplissant les 74 bits restants avec des bits aléatoires.

La caractéristique principale des UUIDv7 est qu’ils sont monotones (chaque valeur suivante est supérieur à la valeur précédente). Cela est dû au fait que la valeur d’horodatage fait partie de l’UUID.

Le grand avantage des UUIDv7 est qu’ils sont naturellement triables ce qui en fait un bon choix pour des identifiants de base de données, comblant une des lacunes des UUID de version précédente. Tout en restant sur 128 bits, donc compatible avec les champs de types UUID précédent.

Les fonctionnalités qui sortent de preview

Les fonctionnalités suivantes sortent de preview (ou du module incubator) et passent en standard :

Aucune !

C’est assez rare pour le surligner. Une partie des fonctionnalités qui sont en preview depuis longtemps sont bloquées en attente du projet Valhalla.

Les fonctionnalités qui restent en preview

Les fonctionnalités suivantes restent en preview (ou en incubator module) :

  • JEP 524PEM Encodings of Cryptographic Objects : deuxième preview, nouvelle API qui apporte le support du format Privacy-Enhanced Mail (PEM) à Java. Quelques changements dans l’API mais les classes PEMEncoder et PEMDecoder proposent toujours la même API.
  • JEP 525Structured Concurrency : sixième preview, nouvelle API permettant de simplifier l’écriture de code multi-threadé en permettant de traiter plusieurs tâches concurrentes comme une unité de traitement unique. Quelques changements mineurs.
  • JEP 526Lazy Constants : deuxième preview, nouvelle API permettant de créer des constante, initializées à la demande.
  • JEP 529Vector API : onzième incubation, API permettant d’exprimer des calculs vectoriels qui se compilent au moment de l’exécution en instructions vectorielles pour les architectures CPU prises en charge. Aucun changement. Il a été acté dans la JEP que la Vector API sera en incubation tant que les fonctionnalités du projet Valhalla ne seront pas disponibles en preview. Ce qui était attendu, car la Vector API pourra alors tirer parti des améliorations de performance et de représentation en mémoire que devrait apporter le projet Valhalla.
  • JEP 530Primitive Types in Patterns, instanceof, and switch : quatrième preview, ajoute le support des types primitifs dans les instanceof et les switch, et enrichit le pattern matching pour supporter des patterns de types primitifs : dans les instanceof, dans les cases des switch, et dans la déconstruction d’un record. Deux changements : amélioration de la définition de l’exactitude inconditionnelle et application de contrôles de dominance plus stricts dans les switch ce qui peut mener le compilateur à rejeter plus de cas qu’auparavant.

Pour les détails sur celles-ci, vous pouvez vous référer à mes articles précédents.

Divers

Divers ajouts au JDK :

  • Process.close() : Ferme tous les flux de lecture et d’écriture et attend la fin du processus. De plus Process implémente AutoCloseable ce qui fait qu’il peut être utilisé dans un try-with-resources.
  • String.compareToFoldCase() et String.equalsToFoldCase() : implémentation d’equals et compareTo qui utilisent le case folding d’Unicode.
  • BigInteger.rootn() et BigInter.rootnAndRemainder() : Renvoie la racine entière n-ième.
  • Duration.MAX et Duration.MIN : durée maximum et minimum supportées.
  • Instant.plusSaturating() : Renvoie une copie de cet instant plus la durée spécifiée, avec une sémantique saturée. Si le résultat est avant MIN, renvoie MIN; si le résultat est après MAX, renvoie MAX; sinon, renvoie plus().
  • ThreadLocalRandom.nextGaussian() : Renvoie un double choisi de manière pseudo-aléatoire à partir d’une distribution gaussienne.
  • Comparator.min(Object, Object) et Comparator.max(Object, Object) : retourne le plus petit ou plus grand object entre les deux objets passés en paramètre.
  • HttpRequest.BodyHandlers.ofFileChannel() : Renvoie un BodyHandler depuis un FileChannel.

La totalité des nouvelles API du JDK 25 peuvent être trouvées dans The Java Version Almanac – New APIs in Java 26.

Des changements internes, de la performance, et de la sécurité

Comme toutes les nouvelles versions de Java, OpenJDK 25 contient son lot d’optimisations de performance et d’améliorations de sécurité.

Côté performance, pas de gros changement, mais pas mal de tous les petits changements. J’ai noté celui-ci qui améliore les performances de ArraytList.addAll() en ajoutant un fast-path au cas où la collection est elle-même une ArrayList qui va copier le tableau sous-jacent, plus d’information dans la PR #28116.

Côté sécurité je n’ai riens noté pour le moment mais je metterais à jour l’article si nécessaire.

JFR Events

Voici les nouveaux événements Java Flight Recorder (JFR) de la JVM :

  • StringDeduplication : pas de description.
  • FinalFieldMutation : pas de description.

Vous pouvez retrouver tous les événements JFR supportés dans cette version de Java sur la page JFR Events.

Conclusion

On reste clairement sur sa faim, cette release apporte très peu de nouvelles fonctionnalités et la plupart des fonctionnalité déjà en preview ou incubator module le restent. On peut quand même noter le support de HTTP/3 et UUIDv7 qui sont les bienvenues pour le développement d’application modernes.

Comme toujours, on se languit du projet Valhalla… bien que de nouvelles rumeurs sont sorties et prédisent une inclusion dans Java 28 des prèmieres fonctionnalités liée au project Valhalla qui sont les nullable type et les value objects !

Pour retrouver tous les changements de Java 26, voir les release notes.

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.