Cet article est issu du blog de Kévin Llopis, développeur Fullstack chez CARBON. Vous pouvez retrouver tous ses articles sur son blog personnel.
Après 6 mois d’attente, une nouvelle version de Java a été publiée le 21 Mars 2023, c’est Java 20. Pour rappel, Java 19 introduisait notamment les Record Patterns et une évolution du Pattern Matching pour le switch. D’ailleurs, ces fonctionnalités permettaient de concevoir nos applications selon le Data-Oriented-Programming (DOP) qui faisait l’objet d’un précédent article. Qu’en est-il aujourd’hui avec Java 20 ?
Dans un premier temps, prenons du recul sur les problèmes auxquels répondent les fonctionnalités de Java 20.
Vous avez dit ThreadLocal ?
Les ThreadLocal existent depuis Java 1.2 et permettent d’associer un objet à chaque thread. D’ailleurs, cette association s’appuie sur ThreadLocal.ThreadLocalMap
pour établir la correspondance entre chaque thread avec les différents ThreadLocal
portant un champ muable.
Par exemple, dans le code suivant on associe une valeur au thread main en s’appuyant sur un ThreadLocal
ainsi qu’une seconde valeur à un nouveau thread :
Cela dit, un thread est susceptible de rester actif jusqu’à l’arrêt complet de l’application, ce qui veut dire qu’un ThreadLocal
inutilisé sera toujours référencé dans la ThreadLocal.ThreadLocalMap
. Ceci peut provoquer une fuite de mémoire, comme par exemple, dans le cas du “classloader leaks”. Bien entendu, un appel à la méthode remove() de ThreadLocal
permet de supprimer l’instance de ThreadLocal.ThreadLocalMap
, mais cela peut souvent être oublié par le développeur.
Donc, les inconvénients du ThreadLocal
sont :
- La muabilité de sa valeur
- Les possibles fuites de mémoire en cas d’oubli de l’appel à
remove()
ScopedValue vs ThreadLocal
Dans le cadre du projet Loom, Java 19 introduisait les Virtual Threads, qui sont un moyen plus rapide et beaucoup moins coûteux que d’utiliser un pool de threads. Cela dit, dans le cas où l’on aurait un million de Virtual Threads et un ThreadLocal
créé pour chacun d’eux, l’espace mémoire utilisé serait très important. D’où la nécessité de créer une solution en vue de partager des données avec des Virtual Threads et sans les inconvénients des ThreadLocal
.
Puis, avec l’arrivée de Java 20, ce sont les Scoped Values qui font leur apparition, qui contrairement aux ThreadLocal
, n’associent pas des variables à un thread.
Une ScopedValue
repose sur les points suivants :
- La valeur est immuable, ce qui a l’avantage de pouvoir être partagée entre plusieurs threads sans effet de bord.
- La valeur est associée avec une clé qui peut être définie par
ScopedValue.where(ScopedValue<T> key, T value)
. - Ce qui est spécifique au
ScopedValue
est que l’accès à la valeur, à partir de la clé, est soumis à des restrictions. En effet, la valeur est accessible uniquement à l’exécution d’unRunnable
ou d’unCallable
.
Comme présenté dans le code suivant, la valeur est accessible dans le Runnable
: ScopedValue.where(ScopedValue<T> key, T value).run(() -> {})
. On peut le vérifier avec la méthode isBound()
.
De ce fait, la valeur n’est pas accessible en dehors du Runnable
et il n’y a pas besoin d’appeler une méthode remove()
comme pour les ThreadLocal
.
Sachez que l’on peut également passer un Runnable
ou un Callable
en troisième argument de :
ScopedValue.where(ScopedValue<T> key, T value, Runnable op)
ScopedValue.where(ScopedValue<T> key, T value, Callable<?> op)
Record Patterns (Seconde preview)
Java 19 avait déjà introduit les Record Patterns qui sont l’un des piliers pour le Data-Oriented Programming (DOP).
Dans Java 20, les Record Patterns comprennent les trois changements suivants :
- Ajout de l’inférence de type sur les Record Patterns génériques
- Ajout des Record Patterns dans les boucles
for
- Suppression des Record Patterns nommés
Pattern Matching pour switch (Quatrième preview)
Pour cette quatrième preview du Pattern Matching dédié au switch
, voici les nouveautés :
- Une exception
MatchException
(à la place deIncompatibleClassChangeError
) est jetée lorsqu’aucuncase
ne correspond à la valeur d’unenum
au runtime. - Simplification des switch cases
- Ajout de l’inférence de type sur les arguments des Record Patterns génériques
Conclusion
La grande nouveauté de Java 20 réside dans les Scoped Values tandis que le reste concerne des améliorations de fonctionnalités toujours en preview comme les Record Patterns et le Pattern Matching appliqué au switch. Cela dit, il ne faut pas oublier que cette version comprend également des évolutions mineures sur Foreign Function & Memory API (Seconde Preview), les Virtual Threads (Seconde Preview), les Structured Concurrency (Second Incubator) ainsi que Vector API (Cinquième Incubator).
Il faut admettre que ces previews nous suivent depuis plusieurs versions déjà. Donc, est-ce que la prochaine version LTS permettra d’aboutir à des fonctionnalités stables notamment pour les Record Patterns et le Pattern Matching ? Verdict en Septembre 2023 !