Aujourd'hui sort la nouvelle version de Java. C'est la première version majeure depuis la LTS mais ne vous inquiétez pas si vous suivez uniquement les LTS, cette version est très petite à moins que vous utilisiez des fonctionnalités en preview ou en incubation (ce qui n'est évidemment pas recommandé).

Region Pinning for G1

Si vous ne vous intéressez pas aux Garbage Collectors (GC) vous ignorez peut-être qu'il en existe plusieurs et qu'on peut choisir celui qui donne les meilleures performances dans notre cas d'usage. Java 22 introduit une "petite" amélioration du garbage collector G1 en liant avec les appels JNI.

Java c'est du code exécuté dans une JVM, mais parfois on a besoin de faire appel à du code natif, ou que du code natif manipule des données en mémoire dans la JVM, on parle ici de section critique. Dans ces cas-là, on doit gérer le fait d'avoir une mémoire partagée hors du contexte de la JVM et la stratégie jusqu'à Java 21 de G1 est de ne se mettre en pause dès qu'on est dans un cas de section critique pour éviter les risques de déplacement mémoire qui pourraient provoquer des erreurs (un morceau de code en C qui affecterait une variable à l'adresse X mais le GC est passé et à déplacée la variable à l'adresse Y). En parallèle tout thread qui provoquerait un appel de GC, est mis en attente le temps que tous les autres threads ne soient plus en attente d'une section critique ce qui peut provoquer des gros problèmes de latence.

À partir de Java 22, on introduit l'idée de marquer (pin) les emplacements mémoire concernées à chaque entrée dans une région critique, de cette façon G1 n'est plus mis en pause et va juste ignorer les sections critiques jusqu'à relâchement de celles-ci.

Unnamed Variables & Patterns

Je vous passe le détail de tous les cas possibles mais en Java comme dans tous les langages, on est parfois obligé de récupérer une variable pour que syntaxiquement ce soit valide, mais on a pas besoin de cette variable. Java 22 introduit la possibilité de simplement la marquer comme ignorée. C'est particulièrement utile avec les Patterns, par exemple :

switch (box) {
    case Box(RedBall _)   -> processBox(box);
    case Box(BlueBall _)  -> processBox(box);
    case Box(GreenBall _) -> stopProcessing();
    case Box(var _)       -> pickAnotherBox();
}

Ici on voit qu'on veut faire des traitements sans avoir spécifiquement besoin de la variable créé à chaque pattern tout en étant obligé de la définir, avec la nouvelle syntaxe _ on peut ignorer cette valeur.

Vous pouvez utiliser plusieurs unamed variables dans le même bloc de code sans aucun problème :

while (q.size() >= 3) {
    var x = q.remove();
    var _ = q.remove();       // Unnamed variable
    var _ = q.remove();       // Unnamed variable
    ... new Point(x, 0) ...
}

Attention, évidemment la variable devient inaccessible, c'est un moyen d'ignorer la variable pas d'éviter d'avoir besoin de nommer celle-ci.

L'exécution de source est maintenant multi-fichier

Pratique pour faire des tests rapides, on peut depuis Java 11 exécuter un fichier .java sans avoir à le compiler avant en .class. Dans ce contexte, on peut mettre plusieurs classes dans un seul fichier .java, mais on ne peut pas importer de classe depuis un autre fichier, le fichier doit être self-contained. À partir d'aujourd'hui cette dernière limitation disparait !

Il est aussi possible de mixer des .class et des .java mais il faudra ajouter les .class dans le classpath !

Quelques previews intéressantes

Comme d'habitude, on a beaucoup de chose en preview. Je vous parle des éléments qui ont évolués les plus intéressant seulement !

Classes implicites et main en méthode d'instance

Seconde preview pour cet JEP qui permettra de lancer un programme Java avec une classe implicite et/ou une méthode main plus simple (méthode de classe, paramètre non défini). Rendant ces deux exemples des fichiers parfaitement valide :

class HelloWorld {
    void main() {
        System.out.println("Hello, World!");
    }
}
void main() {
    System.out.println("Hello, World!");
}

Ça n'a que peu d'intérêt pour des grosses applications déjà en place, mais pour ceux qui apprennent la programmation avec Java, ou juste découvre l'écosystème, ça pourrait leur permettre de découvrir Java en douceur !

Statements before super(...)

Preview très intéressante : permettre d'avoir du code avant le super(...) d'une classe. Ça peut parfois être pratique de pouvoir traiter une donnée avant de la transmettre à la classe parente, on pourra le faire !

Stream Gatherers

Grosse nouveauté à venir : les Gatherers ! C'est une nouvelle API pour les Steams qui va offrir la possibilité de traiter les données de manière un peu différente : on va pouvoir appliquer des regroupements ou avoir des opérations stateful sans pour autant évaluer le stream comme on le fait avec un Collector. l'intérêt étant de garder un seul Stream de donnée et avoir toujours plus d'options d'opérations sur les streams et les plus expressives possible.

Exemple :

Stream.of(1,2,3,4,5,6,7,8,9).gather(Gatherers.fixedWindow(3)).toList();
// [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

À voir quand ce sera intégré mais ça promet !

Class-File API

Aujourd'hui nous n'avons aucune API standard pour manipuler du bytecode. Cette JEP vise à apporter une API standard pour faire ça et à l'avenir se passer des outils tiers comme javassist !

Conclusion

Je fais le choix de passer sur pas mal de previews qui ne sont que des petites mises à jour. Comme souvent récemment, on est face à une petite version, car essentiellement composés de preview ! Mais comme toujours, c'est intéressant de suivre, intéressant de tester, donc n'hésitez pas à upgrade votre JDK !

Sources :

Crédit photo : https://pixabay.com/photos/heart-sand-beach-sea-twenty-two-472281/