Java 20 est passé à la phase de release candidate le 9 février, selon un bulletin de Mark Reinhold d'Oracle, architecte en chef du Java Platform Group. Une deuxième version candidate est prévue pour le 23 février. La disponibilité générale du JDK est prévue pour le 21 mars 2023, dans le cadre de la cadence de publication de six mois d'Oracle pour les éditions Java standard. Pour JDK 20, les développeurs sont encouragés à signaler les bogues via la base dédiée. La période qui s’ouvre doit permettre aux contributeurs de tester, identifier et corriger de nouvelles failles, dans le cadre d’un processus strict et ce avant publication de la version de production.
Les principales fonctionnalités attendues dans JDK 20 :
Scoped values
Cette API en phase d'incubation permet de partager des données immuables au sein d'un même thread ou entre plusieurs threads. Ces valeurs sont préférables aux variables locales aux threads, en particulier quand on utilise un grand nombre de threads virtuels. Scope Value permet de partager des données de manière sûre et efficace entre les composants d'un grand programme sans recourir aux arguments de méthode.
Les objectifs :
- Facilité d'utilisation : fournissez un modèle de programmation pour partager des données à la fois au sein d'un thread et avec des threads enfants, afin de simplifier le raisonnement sur le flux de données.
- Compréhensibilité : rendre visible la durée de vie des données partagées à partir de la structure syntaxique du code.
- Robustesse : assurez-vous que les données partagées par un appelant ne peuvent être récupérées que par des appelés légitimes.
- Performances : traitez les données partagées comme immuables afin de permettre le partage par un grand nombre de threads et d'activer les optimisations d'exécution.
Non-objectifs :
- Ce n'est pas un objectif de changer le langage de programmation Java.
- L'objectif n'est pas d'exiger une migration à partir des variables locales de thread ou de déprécier l'API ThreadLocal existante.
Pour en expliquer la motivation, l'équipe rapporte que les grands programmes Java sont généralement constitués de composants distincts et complémentaires qui doivent partager des données entre eux. Par exemple, une infrastructure Web peut inclure un composant serveur, implémenté dans le style thread par demande, et un composant d'accès aux données, qui gère la persistance. Dans tout le framework, l'authentification et l'autorisation des utilisateurs reposent sur un objet Principal partagé entre les composants. Le composant serveur crée un principal pour chaque thread qui gère une demande, et le composant d'accès aux données fait référence au principal d'un thread pour contrôler l'accès à la base de données.
Normalement, les données sont partagées entre l'appelant et l'appelé en les transmettant comme arguments de méthode, mais cela n'est pas viable pour un principal partagé entre le composant serveur et le composant d'accès aux données car le composant serveur appelle d'abord le code utilisateur non approuvé. Nous avons besoin d'un meilleur moyen de partager les données du composant serveur vers le composant d'accès aux données plutôt que de les connecter à une cascade d'invocations de méthodes non fiables.
Disponibles en seconde preview, les Record Patterns améliorent le langage de programmation Java avec des motifs pour déconstruire les valeurs d'enregistrement Record Values. Les motifs d'enregistrement (record patterns) et les motifs de type (type patterns) peuvent être imbriqués pour permettre une forme déclarative, puissante et composable de navigation et de traitement des données.
Pour être plus précis, les Record Patterns ont été proposés en tant que fonction en preview par JEP 405 et livrés dans JDK 19. Ce JEP propose une deuxième preview avec d'autres améliorations basées sur l'expérience et les commentaires continus.
Les principaux changements depuis la première preview sont les suivants*:
- Ajout de la prise en charge de l'inférence des arguments de type des modèles d'enregistrement génériques,
- Ajout de la prise en charge des modèles d'enregistrement pour qu'ils apparaissent dans l'en-tête d'une instruction for améliorée, et
- Suppression de la prise en charge des modèles d'enregistrement nommés.
Les objectifs sont d'étendre le filtrage de motifs pour exprimer des requêtes de données plus sophistiquées et composables, sans modifier la syntaxe ou la sémantique des motifs de type. Parmi les principales modifications apportées depuis le premier aperçu livré avec le JDK 19, on peut citer le support de l’inférence du type paramétré pour les patterns de record generic, le support des record patterns dans les boucles for (enhanced for statements) et la suppression du support des patterns de record nommés.
Pour en expliquer les motivations, l'équipe explique que dans JDK 16, JEP 394 a étendu l'opérateur instanceof pour prendre un modèle de type et effectuer une correspondance de modèle. Cette extension modeste permet de simplifier l'idiome familier instanceof-and-cast*:
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | // Old code if (obj instanceof String) { String s = (String)obj; ... use s ... } // New code if (obj instanceof String s) { ... use s ... } |
Dans le nouveau code, obj correspond au modèle de type String s si, au moment de l'exécution, la valeur de obj est une instance de String. Si le modèle correspond, l'expression instanceof est true et la variable de modèle s est initialisée à la valeur de obj convertie en chaîne, qui peut ensuite être utilisée dans le bloc contenu.
Dans JDK 17, JDK 18 et JDK 19, l'équipe a étendu l'utilisation des modèles de type pour changer également les étiquettes de casse, via JEP 406, JEP 420 et JEP 427.
Les modèles de type suppriment de nombreuses occurrences de casting (une méthode ou un processus qui convertit un type de données en un autre type de données dans les deux sens manuellement et automatiquement) d'un coup. Cependant, ils ne sont que la première étape vers un style de programmation plus déclaratif et axé sur les données. Comme Java prend en charge de nouvelles façons plus expressives de modéliser les données, la correspondance de modèles peut rationaliser l'utilisation de ces données en permettant aux développeurs d'exprimer l'intention sémantique de leurs modèles.
Foreign function and memory API
En seconde preview également, cette API permet aux programmes Java d’interagir avec du code et des données en dehors du runtime Java, notamment aux applications Java d'appeler des bibliothèques natives et de traiter des données natives sans la fragilité et les risques de la JNI (Java Native Interface).
L'API Foreign Function & Memory (FFM) combine deux API d'incubation antérieures*: l'API Foreign-Memory Access (JEP 370, 383 et 393) et l'API Foreign Linker (JEP 389). L'API FFM a été incubée dans JDK 17 via JEP 412, elle a été ré-incubée dans JDK 18 via JEP 419, et elle a été proposée en préversion pour la première fois dans JDK 19 via JEP 424. Cette JEP propose d'incorporer des améliorations basées sur les commentaires et de proposer en seconde preview l'API dans JDK 20. Dans cette version*:
- Les abstractions MemorySegment et MemoryAddress sont unifiées (les adresses mémoire sont désormais modélisées par des segments mémoire de longueur nulle) ;
- La hiérarchie scellée MemoryLayout est améliorée pour faciliter l'utilisation avec la correspondance de modèles dans les expressions et instructions switch (JEP 433), et
- MemorySession a été divisé en Arena et SegmentScope pour faciliter le partage de segments au-delà des limites de maintenance.
Les objectifs :
- Facilité d'utilisation : remplacer l'interface native Java (JNI) par un modèle de développement Java pur supérieur.
- Performances : fournit des performances comparables, voire supérieures, aux API existantes telles que JNI et sun.misc.Unsafe.
- Généralité : fournit des moyens d'opérer sur différents types de mémoire étrangère (par exemple, la mémoire native, la mémoire persistante et la mémoire de tas gérée) et, au fil du temps, de prendre en charge d'autres plates-formes (par exemple, 32 bits x86) et des fonctions étrangères écrites dans d'autres langages que C (par exemple, C++, Fortran).
- Sécurité : autoriser les programmes à effectuer des opérations non sécurisées sur la mémoire étrangère, mais avertir les utilisateurs de ces opérations par défaut.
Cette API n'a pas pour objectif de :
- réimplémenter JNI en plus de cette API, ou modifier JNI de quelque manière que ce soit*;
- réimplémenter les anciennes API Java, telles que sun.misc.Unsafe, en plus de cette API*;
- fournir des outils qui génèrent mécaniquement du code Java à partir de fichiers d'en-tête de code natif*; ou
- modifier la manière dont les applications Java qui interagissent avec les bibliothèques natives sont empaquetées et déployées (par exemple, via des fichiers JAR multiplateformes).
Qu'est-ce qui a motivé son développement ? La plate-forme Java a toujours offert une base riche aux développeurs de bibliothèques et d'applications qui souhaitent aller au-delà de la JVM et interagir avec d'autres plates-formes. Les API Java exposent des ressources non Java de manière pratique et fiable, que ce soit pour accéder à des données distantes (JDBC), appeler des services Web (client HTTP), servir des clients distants (canaux NIO) ou communiquer avec des processus locaux (sockets de domaine Unix). Malheureusement, les développeurs Java sont toujours confrontés à des obstacles importants pour accéder à un type important de ressources non Java*: le code et les données sur la même machine que la JVM, mais en dehors de l'environnement d'exécution Java.
Virtual threads
En seconde preview, les Virtual threads sont des threads légers qui demandent moins d'effort d'écriture, de maintenance et d'observation des applications concurrentes à haut débit. Depuis le premier aperçu livré avec le JDK 19, l'API a connu des changements mineurs (quelques modifications rendues dans l’API permanentes dans le JDK 19) et des dégradations de ThreadGroup (également rendues permanentes dans le JDK 19).
Les objectifs :
- activer les applications serveur écrites dans le style simple thread par demande pour évoluer avec une utilisation matérielle quasi optimale.
- activer le code existant qui utilise l'API java.lang.Thread pour adopter des threads virtuels avec un minimum de modifications.
- faciliter le dépannage, le débogage et le profilage des threads virtuels avec les outils JDK existants.
Les développeurs Java se sont appuyés sur les threads comme élément de base des applications serveur simultanées pendant près de trois décennies. Chaque instruction de chaque méthode est exécutée à l'intérieur d'un thread et, puisque Java est multithread, plusieurs threads d'exécution se produisent en même temps. Le thread est l'unité de simultanéité de Java : un morceau de code séquentiel qui s'exécute en même temps que — et largement indépendamment — d'autres unités de ce type. Chaque thread fournit une pile pour stocker les variables locales et coordonner les appels de méthode, ainsi que le contexte lorsque les choses tournent mal*: les exceptions sont levées et interceptées par les méthodes du même thread, de sorte que les développeurs peuvent utiliser la trace de la pile d'un thread pour découvrir ce qui s'est passé. Les threads sont également un concept central pour les outils*: les débogueurs parcourent les instructions dans les méthodes d'un thread et les profileurs visualisent le comportement de plusieurs threads pour aider à comprendre leurs performances.
Structured Concurrency
Cette API vient simplifier la programmation multithread et traite plusieurs tâches exécutées dans différents threads comme une seule unité de travail. La gestion et l'annulation des erreurs sont rationalisées, ce qui améliore la fiabilité et l'observabilité. Le seul changement depuis son incubation dans le JDK 19 est que StructuredTaskScope a été mis à jour pour prendre en charge l'héritage des Scoped Values par les threads créés dans la portée d'une tâche. Cette fonctionnalité est en cours de réincubation.
Les développeurs gèrent la complexité en décomposant les tâches en plusieurs sous-tâches. Dans le code monothread ordinaire, les sous-tâches s'exécutent séquentiellement. Cependant, si les sous-tâches sont suffisamment indépendantes les unes des autres et s'il y a suffisamment de ressources matérielles, la tâche globale peut être exécutée plus rapidement (c'est-à-dire avec une latence plus faible) en exécutant les sous-tâches simultanément. Par exemple, une tâche qui compose les résultats de plusieurs opérations d'E/S s'exécutera plus rapidement si chaque opération d'E/S s'exécute simultanément dans son propre thread. Les threads virtuels (JEP 425) rendent rentable le fait de dédier un thread à chacune de ces opérations d'E/S, mais la gestion du grand nombre de threads qui peuvent en résulter reste un défi.
Correspondance de modèles pour les expressions et déclarations switch
En quatrième préversion (elle était déjà présente dans les JDK 17, JDK 18 et JDK 19), la fonctionnalité permet l'expression concise et sûre de requêtes complexes orientées données. Elle pourra évoluer en continu avec les Record Patterns, ce qui permettra des améliorations continues basées sur l'expérience et le feedback. Parmi les principales modifications apportées au Pattern matching for switch depuis le troisième aperçu, on peut citer une grammaire simplifiée pour les étiquettes de switch et la prise en charge de l'inférence des arguments de type pour les generic patterns et les record patterns dans les déclarations et expressions de switch. De plus, un switch exhaustif sur une classe enum provoque désormais une MatchException plutôt qu'une IncompatibleClassChangeError si aucune étiquette de switch ne s'applique au moment de l'exécution.
Source : Inside Java