Java 10 : quoi de neuf ?

Java 10 : quoi de neuf ?

Maintenant que Java 10 est sorti, il est temps de se pencher sur les nouveautés de cette version. Comme pour mon précédent article sur java 9, je vais me pencher principalement sur les changements qui impacterons les développeurs utilisant Java en laissant de côté les changements internes/anecdotique/sur des API peu utilisés.

Le nouveau « release train »

Une nouveauté toute particulière est la manière dont Java va être releasé depuis Java 10 : Java va passer d’un système de feature release tous les deux ans (qui en réalité était plus proche de tous les trois ans) à un release train avec une release tout les 6 mois.

Précédemment, un ensemble de fonctionnalités était défini pour aller dans une version de Java et celle-ci n’était releasée que quand toutes ces fonctionnalités été prêtes, il y avait souvent beaucoup de chose dans une nouvelle version de Java, ce qui en faisait une version difficile à livrer et un gap assez important pour les utilisateurs de Java à passer.

A partir de Java 10 : une version tous les 6 mois en release train : les fonctionnalités sont développées dans des branches de développement spécific et quand elles sont prête elles sont mergée dans la branche principale. A la date de la release, tout ce qui a été mergé part en release. Avec un système comme cela on aura plus de petite release mais plus régulière.
Dernier point : chaque version de Java n’auras pas forcément un support long, le support d’une version sera jusqu’à la version suivante (donc 6 mois) sauf pour une version tout les trois ans qui sera en Long Term Support (LTS), Java 11 sera la première version LTS.

On peu regretter que la première LTS ne soit que la version 11, la version 9 qui apporte énormément de changement ne sera supportée que 6 mois ce qui en fait une version que personne ne va réellement utiliser en production. De même, comme il n’y aura pas d’overlap entre les version non-LTS, un utilisateur sera obligé de passer à la nouvelle version tout de suite ou de rester sur les version LTS : dans ce cas, Java va passer d’une features release tous les 2-3 ans à un release train avec une release LTS tous les 3 ans …

Ce système de release train et de version LTS est proche de celui que fait Ubuntu même si Java a gardé un numéro de version (bien qu’un système basé sur les dates à été envisagé puis abandonné).

Voir l’article de Mark Reinhold expliquant en détail le nouveau release train https://mreinhold.org/blog/forward-faster
Voir les infos dans la JEP : http://openjdk.java.net/jeps/322

Les nouveautés du language pour les développeurs

Local-Variable Type Inference

C’est LA grande nouveauté de Java 10 : la possibilité d’utiliser le mot clé var à la place d’une déclaration standard de variable, à l’intérieur d’une méthode (variable locale) quand le type peut être inféré par le compilateur. Var peut être aussi utilisé dans la déclaration des boucles for et du try-with-resource.

Java reste un language statiquement typé, mais quand on déclare une variable puis on l’instancie sur la même ligne, la déclaration de type est redondante! Le mot clé var va donc pouvoir la remplacer.

En Java 9 :

MyComplexType obj = new MyComplexType();
Map<String,List<MyComplexType>> map = new HashMap<String,List<MyComplexType>>();

En Java 10 avec le mot clé var :

var obj = new MyComplexType();
var map = new HashMap<String,List<MyComplexType>>();

Meilleur visibilité (entre autre, les deux variables sont indentée au même niveau), moins de cérémonie, concision de l’écriture, …

Pour l’instant, le mot clé var est limité aux variables locale aux méthode et il n’y a pas d’équivalent « immuable« , le travail sur l’immuabilité en Java étant en cours de réflexion il aurait été prématuré de proposer un mot clé pour des variable finale (val ou let …).

Stuart Marks a publié des guidelines sur l’utilisation du mot clé var :  http://openjdk.java.net/projects/amber/LVTIstyle.html

Plus d’info dans la JEP : http://openjdk.java.net/jeps/286

Copy factory methods

L’API Collection a été enrichie de méthodes statiques permettant la copie de collection existantes : List.copyOf(), Set.copyOf(), et Map.copyOf().

Dans les trois cas la collection retournée sera une collection immuable. Si la collection existante était déjà une collection immuable, elle sera retournée directement (car il n’y a pas d’intérêt à créée une copie d’une collection immuable qui sera elle-même immuable …), sinon une nouvelle collection immuable sera créée.

Attention, les collections sont immuable pas les objets qu’elles contiennent!

Voici, pour exemple, l’implémentation actuelle de List.copyOf() :

static <E> List<E> copyOf(Collection<? extends E> coll) {
    if (coll instanceof ImmutableCollections.AbstractImmutableList) {
        return (List<E>)coll;
    } else {
        return (List<E>)List.of(coll.toArray());
    }
}

Plus d’info dans le ticket JIRA : https://bugs.openjdk.java.net/browse/JDK-8177290

Collectors to unmodifiable List

Dans la même mouvance que le précédent changement, les collectors de l’API Stream ont été enrichit pour permettre la création de collections immuable :

  • Collectors.toUnmodifiableList()
  • Collectors.toUnmodifiableSet()
  • Collectors.toUnmodifiableMap(keyFunc, valueFunc)
  • Collectors.toUnmodifiableMap(keyFunc, valueFunc, mergeFunc)

Plus d’info dans le ticket JIRA :  https://bugs.openjdk.java.net/browse/JDK-8184690

Optional.orElseThrow()

Optional.orElseThrow() est maintenant la manière privilégiée (au détriment de Optional.get()) pour récupérer un élément dans un Optional. Son nom fait clairement référence au fait que si il n’y a pas d’élément, une exception sera lancée (ce qui est le cas pour Optional.get() mais souvent oublié par les développeurs l’utilisant).

Cela fait parti d’une réflexion plus large sur Optional, on devrait voir d’autres ajouts dans cette classe dans les prochaines releases …

Plus d’info dans le ticket JIRA : https://bugs.openjdk.java.net/browse/JDK-8140281

Reader.transferTo(Writer)

Un nouvelle méthode à la classe Reader de directement transférer tout les caractère d’un Reader à un Writer :

Reader reader = new FileReader("from.txt");
Writer writer = new FileWriter("to.txt");
reader.transferTo(writer);

Les principaux changements axés performance

Parallel Full GC for G1

C’est le changement le plus important en terme de performance.

G1 est depuis Java 9  l’algorithme de Garbage Collection par défaut. Hors dans celui-ci, quand le collector n’arrive plus à nettoyer assez rapidement la heap de manière concurrente, il déclenche un Full GC qui était mono-threadé. Depuis Java 10 l’implémentation de celui-ci a été changé en multi-threadé, le nombre de threads étant définit par -XX:ParallelGCThreads

Plus d’info dans la JEP : http://openjdk.java.net/jeps/307

Thread-Local Handshakes

Jusqu’à Java 9, la seul manière de pouvoir faire des actions sur plusieurs threads en même temps (récupérer un thread dump, gestion des locks, …) était de mettre tous les threads dans un safepoint. Cette opération est couteuse et nécessite de coordonner tous les threads de l’application.

Depuis java 10 : le mécanisme de Handshakes permet d’exécuter des callbacks sur des threads sans nécessairement passer par un safepoint.

Cette fonctionalité assez bas niveau ouvre la porte à d’autres optimisations au sein de la JVM qu’on devrait voir arriver dans les prochaines releases.

Plus d’info dans la JEP : http://openjdk.java.net/jeps/312

Divers

Experimental Java-Based JIT Compiler

Cette nouvelle fonctionnalité permet de changer le Just In Time (JIT) compiler de Java vers un JIT écrit en Java : Graal

Le JIT est la partie de la JVM qui permet d’optimiser le code qui tourne dans la JVM au fil de son execution, il est aujourd’hui écrit en C++ et devient assez difficile à maintenir.

Graal est un nouveau projet d’Oracle qui fait parti d’un projet plus vaste : Metropolis, dont le but est de faire du Java on Java. Donc de faire tourner Java avec une JVM en Java (aujourd’hui la JVM est principalement écrite en C++). Graal est un compilateur, écrit en Java, qui depuis du bytecode Java (du code compilé Java) peut généré du code natif optimisé. Son implémentation en Java en facilite l’écriture et la maintenance. Il peut être vu comme le futur du JIT de la JVM, il est pour l’instant en phase bêta mais peut être utilisé facilement depuis Java 10  via ces options JVM :

-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler

Un article très intéréssant d’introduction à Graal : http://chrisseaton.com/truffleruby/jokerconf17/

Plus d’info dans la JEP : http://openjdk.java.net/jeps/317

Heap Allocation on Alternative Memory Devices

D’un côté, nos applications ont toujours besoin de plus en plus de mémoire, même si nos serveurs en on de plus en plus … il n’y en a jamais assez! De l’autre côté, il existe désormais des devices de stockage qui ont des performances proches de la DRAM.

Cette nouvelle fonctionnalité, implémentée par Intel (qui fournit une implémentation pour ses cartes flash haute performance NV-DIM 3D XPoint) permet de démarrer une JVM en utilisant une Heap qui n’est pas en RAM.

Plus d’info dans la JEP : http://openjdk.java.net/jeps/316

Application Class-Data Sharing

Cette fonctionnalité permet de partager entre plusieurs JVM tournant sur une même machine les meta-information des classes (class metadata, une partie du metastore). On optimise alors le démarrage et l’empreinte mémoire de ces JVM.

Cette fonctionnalité peut être très pratiques au temps du cloud et de la containerisation …

Plus d’info dans la JEP : http://openjdk.java.net/jeps/310

Pour aller plus loins

Une liste exhaustive (je penses) de tous les changements de cette release : https://www.azul.com/109-new-features-in-jdk-10

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.