Java.Next

1

Si vous avez suivi un petit peu l’actualité de Java vous avez dû remarquer qu’il s’est passé pas mal de choses cette dernière année : Java 9 est sorti il y a un an avec pas mal de nouveautés (dont la tant attendue modularité du JDK) et n’est déjà plus supporté depuis 6 mois, Java 10 est sorti il y a 6 mois et n’est plus supporté non plus, Java 11 vient de sortir et est LTS (Long Term Support). Oracle fournit deux distributions de Java : Oracle et OpenJDK et propose du support étendu pour ceux qui le veulent. Java 8 (la version la plus utilisée actuellement) ne sera plus supporté à partir de janvier 2019!

Pour ceux qui sont un peu perdus là-dedans, cet article est fait pour vous ! Je vais tenter d’éclaircir le nouveau mode de gouvernance de Java (cycle des release, support, distribution) et de vous présenter les principales nouveautés des versions 9, 10 et 11 en faisant le focus sur les changements à destination des développeurs.

Le nouveau rythme des versions

Les architectes du langage Java ont fait un constat : le rythme des versions de Java jusqu’à la version 8 était d’une tous les 3 ans environs, ce faisant on avait peu de versions avec à chaque fois beaucoup de fonctionnalités.  C’était donc compliqué de livrer une nouvelle version de Java; et compliqué pour les développeurs de faire la montée de version de Java, pour leur application, au vu du nombre de changements inclus dans chaque nouvelle version. Comme une version avait un ensemble de fonctionnalité prévue, si une fonctionnalité prenait plus de temps à être développée, elle retardait la sortie de la nouvelle version.

De plus, ce rythme ne collait plus avec la réalité du monde de l’informatique où tout va de plus en plus vite ! Ils ont donc décidé d’avoir une release tous les 6 mois (donc un calendrier fixe), s’inspirant de ce que fait Ubuntu par exemple.

Dans chaque release, toutes les fonctionnalités prêtes sont incorporées, celles qui ne sont pas prêtes partiront dans la suivante (plus de release en retard).

Chaque release sera maintenue 6 mois par Oracle (libre à d’autres éditeurs de les supporter plus longtemps). Pour les entreprises qui ne peuvent/ne veulent pas tenir le rythme il y aura tous les trois ans une version dite LTS — Long Term Support — qui sera maintenue trois ans.

Le but de ceci : livrer de nouvelles fonctionnalités en continu (on parle alors de release train), forcer les utilisateurs à migrer, et simplifier lesdites migrations, car le scope de chaque release est plus petit.

Mon avis sur la question : il faut vivre avec son temps. Tout le monde ou presque fait de l’intégration continue et/ou du déploiement continu, donc passer d’une version à l’autre de Java ne doit pas être un problème. Je conseille donc, à chaque nouveau projet, de passer sur la version de Java la plus récente. Ceux qui sont réfractaires au changement peuvent rester sur les LTS mais en tout cas … il faut dépasser Java 8 et embrasser le nouveau rythme des releases.

Posez-vous la question pour ceux qui font du JavaScript ou du TypeScript : quand migrez-vous ? Ubuntu et Angular font bien une version tous les 6 mois non ?

Donc Oracle s’est juste aligné sur les bonnes pratiques du marché en termes de version.

Ce nouveau rythme a permis à Oracle de fournir dans le JDK, une implémentation de TLS 1.3 en quelques mois ce qui aurait été impensable il y a quelques années.

Les changements en termes de distribution

Oracle fournit deux distributions de Java :

Ces deux distributions sont identiques en termes de fonctionnalités, Oracle ayant opensourcé les quelques fonctionnalités commerciales qui restaient dans Java (Java Flight Recording, Mission Control, CDS, …).

D’autres vendeurs proposent leur propre distribution :

Nous avons désormais le choix dans la distribution, et dans le mode de support : communautaire ou payant (et fourni par plusieurs vendeurs différents !).

Les nouveautés de Java 9

La modularisation du JDK

Un système de module a été intégré à Java 9, le JDK en lui-même a été modularisé ce qui permet de mettre des limites claires à chaque API qui déclare alors de quelles autres parties du JDK elles dépendent, et quels services elles exposent. Le but de la modularisation est de permettre une évolution plus rapide du JDK, de pouvoir connaitre plus facilement les dépendances entres les différentes parties du JDK, et de pouvoir “cacher” les API internes du JDK. Cela ouvre aussi la porte à de nouvelles fonctionnalités telles que la possibilité de créer des librairies Java native, avec uniquement les parties du JDK utilisé par un programme, via l’outil jlink.

Bien que ce soit la principale nouvelle fonctionnalité de Java 9, ce n’est pas la seule, et loin de là !

Un client HTTP/2 en stade expérimental

Ce nouveau client HTTP vient remplacer le très vieux HTTPUrlConnection intégré dans le JDK et quasiment jamais utilisé directement. Il implémente HTTP/2, propose une API fluent, et permet un mode asynchrone ou synchrone.

Une refonte de l’API Process via ProcessHandle

Gérer depuis java l’appel à un programme (process) externe a toujours été compliqué. Surtout si on veut faire des opérations qui semblent basiques, mais qui n’ont pas été prévues dans l’implémentation actuelle (récupérer le PID, killer un process, récupérer la ligne de commande …).

L’API Process a été grandement améliorée pour permettre toutes ces opérations, sur le process de la JVM (ProcessHandle.current()), ou un process fils créé via Runtime.getRuntime().exec(« your_cmd »). De plus, comme toujours avec java, c’est compatible avec les différents OS supportés par Java (et donc avec Windows ET Linux !).

En voici quelques exemples d’utilisations en Java 9 :

Méthode factory de création de collections

Ces nouvelles méthodes permettent de créer facilement des petites collections immuables.

Une implémentation des Reactive Stream

La classe Flow propose trois interfaces pour implémenter vos stream réactives :

  • Publisher : Produit des messages que les subscriber vont consommer. La seule méthode est subscribe(Subscriber).
  • Subscriber : Souscrit à un publisher pour recevoir des messages (via la méthode onNext(T)), des messages d’erreur (onError(Throwable)), ou un signal comme quoi il n’y aura plus de messages (onComplete()). Avant toute chose, le publisher doit appeler onSubscription(Subscription).
  • Subscription : La connexion entre un publisher et un subscriber. Le subscriber va l’utiliser pour demander des messages (request(long)), ou pour rompre la connexion (cancel()).

Un tutoriel est disponible ici : https://community.oracle.com/docs/DOC-1006738

jshell: The Java Shell (Read-Eval-Print Loop)

Dans le but de réduire le cérémonial nécessaire à tester le langage Java, un shell (ou repl : read-eval-print-loop) a été introduit dans Java pour directement tester, depuis la ligne de commande, le langage Java.

Exemple ci-dessous.

Autres API

De nombreuses API existantes ont été améliorées par l’ajout de nouvelles méthodes, on peut citer :

  • Des ajouts à l’API de Stream : iterate(), ofNullable() et dans les Collectors : filtering(), flatMapping()
  • Des ajouts à Optional : or(Supplier), ifPresent(Consumer), ifPresentOrElse(Consumer, Runnable), stream()
  • La création de Stream à partir d’une LocalDate : datesUntil()

Performance

Chaque version de Java se veut plus performante et moins gourmande en mémoire. Java 9 apporte aussi son lot de nouveauté sur ces sujets :

  • Improve Contended Locking : optimisation des monitors Java (optimisation des lock).
  • Compact Strings : revue de l’implémentation des String en Java pour en proposer une version plus compacte en cas de String ISO-8859-1 (ou Latin-1). Les String Java sont stockées en UTF-16 par défaut : chaque caractère est alors stocké sur deux octets. À la création de la String, si elle est compatible ISO-8859-1 elle sera stockée de manière compacte avec chaque caractère sur un octet et non deux.
  • Indify String Concatenation : La concaténation des chaînes de caractères a été optimisée en interne de la JVM.
  • Passage du garbage collector par défaut du Parallel GC au G1 GC

Pour aller plus loin

La rétrocompatibilité de Java 9

Java 9 : quoi de neuf

Les nouveautés de Java 10

Local-Variable Type Inference

C’est la nouvelle fonctionnalité de Java 10 : l’introduction du mot clé var permettant de remplacer le type d’une variable locale quand celle-ci peut être inférée par le compilateur.

Java reste un langage 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.

À la compilation, var sera remplacé par le type de la variable par le compilateur : il n’y a donc pas de changement au runtime.

En Java 9 :

En Java 10 avec le mot clé var :

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

Copy factory methods

L’API Collection a été enrichie de méthodes statiques permettant la copie de collections 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éer une copie d’une collection immuable qui sera elle-même immuable …), sinon une nouvelle collection immuable sera créée.

Collectors to unmodifiable List

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

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

Pour aller plus loin

Java 10 : quoi de neuf

Les nouveautés de Java 11

HTTP Client (Standard)

Le nouveau client HTTP introduit en expérimental dans Java 9 a été inclus en standard dans Java 11, dans son propre package java.net.http.

Son implémentation a été totalement revue et est basée sur une API totalement asynchrone.

Launch Single-File Source-Code Programs

Dans le but de réduire le cérémonial nécessaire pour utiliser Java, on peut désormais lancer un programme basique Java (écrit dans un seul fichier .java) directement, sans passer par l’étape compilation, via la ligne de commande java.

Une compilation en mémoire sera alors réalisée du programme avant son exécution.

Les nouveaux GCs

Deux nouveaux Garbage Collector (GC) ont été intégrés à Java :

  • Epsilon : un GC qui ne nettoie rien! Il alloue les objets jusqu’à ce qu’il ne puisse plus, puis arrête la JVM. Dédié à une utilisation expérimentale dans le domaine du développement des GC.
  • ZGC (Zero GC) : sorti des laboratoires de recherche d’Oracle : Oracle Labs. Ce nouveau GC vise des pauses de moins de 10ms pour des applications pouvant utiliser jusqu’à des To de mémoire. Ce n’est pas un remplaçant de G1 mais un GC dédié aux très très grosses heap.

En plus de ces deux GC, un grand travail a été réalisé sur G1, le GC par défaut depuis Java 9, pour le rendre plus performant et moins gourmand en mémoire.

Selon l’auteur d’une partie de ces changements, en passant de Java 8 à Java 11, on aurait des pauses 60% plus basses « gratuitement » pour une utilisation mémoire grandement réduite.

Autres API

De nombreuses API existantes ont été améliorées par l’ajout de nouvelles méthodes, on peut citer :

  • Des méthodes pour comparer CharSequence, StringBuilder, et StringBuffer : ajout de compareTo().
  • isEmpty() : retourne true si la valeur n’est pas présente.
  • Ajout de méthodes à nio.file.Files pour lire/écrire depuis une String.
  • not() : négation d’un prédicat.
  • convert(Duration) : conversion d’une Duration vers une TimeUnit.
  • String::repeat : créé une String qui est la répétition de la String sur laquelle la méthode est appelée.
  • String::strip, String::stripLeading, String::stripTrailing : créé une String en retirant les espaces (tel que défini par isWhitespace) de la String sur laquelle la méthode est appelée.
  • String::isBlank : retourne true si la String est vide ou ne contient que des espaces (tel que défini par isWhitespace).
  • String::lines : retourne une Stream avec les lignes de la String. Plus performant que split car réalise le split de manière lazy.

Pour aller plus loin

Java 11 : quoi de neuf

Conclusion

Le nouveau rythme des releases nous force à aller de l’avant et c’est tant mieux ! De plus en plus d’organisations contribuent au développement de Java dans ses fonctionnalités, via la diffusion de distributions, et en offrent du support.

L’écosystème s’élargit !

Pour tirer parti des nouvelles fonctionnalités, et des optimisations en termes de performance et de sécurité, il nous faut migrer au fur et à mesure sur ces nouvelles versions.

Encore heureux pour nous, nos pipelines modernes de développement et nos pratiques d’industrialisation nous permettent de le faire en toute sérénité via les outils à notre disponibilité : usine de développement (CI/CD), automatisation de la production (ansible, docker, …), orchestration de la production (kubernetes), monitoring (Prometheus, Istio, …), …

Donc, n’ayant pas peur et passons à Java 11 (version OpenJDK bien sûr) !

Et pour ceux qui auraient peur dans l’avenir de Java et dans la pérennité de son modèle Open Source, je vous invite à lire la réponse d’experts reconnus dans la communauté sur le sujet : Java Is Still Free.

Partagez cet article.

A propos de l'auteur

Un commentaire

  1. Pingback: Java.Next | Lettres ouvertes

Ajouter un commentaire