URL: https://linuxfr.org/news/java-14-tombe-le-masque Title: Java 14 tombe le masque Authors: Nonolapéro theojouedubanjo, olivier-maury, Benoît Sibaud, Davy Defaud et Ysabeau 🧶 Date: 2020年03月09日T23:11:00+01:00 License: CC By-SA Tags: java, openjdk, grafana et fosdem Score: 36 À quelques jours du printemps, une nouvelle version de Java arrive avec son lot de corrections, améliorations, nouveautés et retraits. Voilà six mois que [Java 13](https://linuxfr.org/news/sortie-d-openjdk-13) a apporté ses quelques nouveautés. Cette nouvelle itération est bien plus riche aussi bien sur les fonctionnalités définitives que sur celles en cours de maturation. Au programme pas moins de [16 JEP](https://openjdk.java.net/projects/jdk/14/) intègrent le langage. Seulement une partie sera détaillée dans la suite de dépêche. ---- [Les JEPs OpenJDK 14](https://openjdk.java.net/projects/jdk/14/) [L’ensemble des améliorations et des corrections](https://builds.shipilev.net/backports-monitor/release-notes-14.txt) ---- # Les nouveautés définitives # Avec la nouvelle cadence de versionnage, les nouveautés arrivent plus tôt mais dans un état non définitif et profitent des retours d’expérience des utilisateurs. ## Temps de démarrage et empreinte mémoire ## Depuis plusieurs versions, les temps de démarrage et l’empreinte mémoire diminuent. Il est possible d’espérer un gain d’une dizaine de pourcents sur le temps de démarrage, c’est toujours ça de pris ! Côté empreinte mémoire, en revanche, la baisse est plus conséquente, de l’ordre de 30 % à 40 %. Ces améliorations sont natives, il n’est pas nécessaire d’ajouter des options. Pour plus de détails, une [présentation](https://linuxfr.org/users/nonolapero/liens/presentation-sur-l-amelioration-des-performances-de-java-depuis-plusieurs-versions) et un [article](https://cl4es.github.io/2019/11/20/OpenJDK-Startup-Update.html). ## Du côté des ramasse‐miettes ## ### G1 ### G1 est le ramasse‐miettes par défaut depuis Java 8 et il progresse de version en version à tous les niveaux (temps de réponse, gestion de la mémoire). Je vous laisse regarder cette [présentation](https://fosdem.org/2020/schedule/event/g1/) ou le [support](http://cr.openjdk.java.net/~sjohanss/slides/fosdem_2020_-_g1.pdf). Cette progression est une bonne raison pour ne plus rester sur Java 8, car aucune amélioration n’est portée sur les versions antérieures. ### Les ramasse‐miettes expérimentaux ### ZGC (disponible depuis Java 11) fonctionne sur les trois principaux systèmes d’exploitation et il devrait bientôt ne plus être expérimental si l’on en croit cette [JEP](https://openjdk.java.net/jeps/8209683). L’idée derrière ZGC est de proposer un ramasse‐miettes à faible latence et qui peut aussi bien gérer des petites ou des grosses quantités de mémoire. Shenandoah est un autre ramasse‐miettes à faible latence intégré depuis Java 12, son objectif est d’avoir des temps de pause identiques quelle que soit la quantité de mémoire à libérer. Si vous voulez savoir comment ça fonctionne et avoir un état d’avancement du projet, je vous laisse regarder cette [présentation](https://fosdem.org/2020/schedule/event/shenandoah/) et pour les explications plus détaillées c’est [ici (partie 1)](https://developers.redhat.com/blog/2020/03/04/shenandoah-gc-in-jdk-14-part-1-self-fixing-barriers/), puis [là (partie 2)](https://developers.redhat.com/blog/2020/03/09/shenandoah-gc-in-jdk-14-part-2-concurrent-roots-and-class-unloading/). ## Switch statement et switch expression ## Les _switch expression_ et _switch statement_ sont arrivées dans la version 12, ont été revues dans la version 13 et sont définitives dans cette version 14 (voir la [JEP 361](https://openjdk.java.net/jeps/361)). Avant, on devait écrire : ```java public enum Event { PLAY, PAUSE, STOP } String log; switch (event) { case PLAY: log = "User has triggered the play button"; break; case STOP: case PAUSE: log = "User needs a break"; break; default: String message = event.toString(); LocalDateTime now = LocalDateTime.now(); log = "Unknown event " + message + " logged on " + now; break; } ``` Et maintenant, cette syntaxe est possible : ```java var log = switch (event) { case PLAY -> "User has triggered the play button"; case STOP, PAUSE -> "User needs a break"; default -> { String message = event.toString(); LocalDateTime now = LocalDateTime.now(); yield "Unknown event " + message + " logged on " + now; } }; ``` Avec cette nouvelle forme : * il n’y a plus de risque d’oublier un `break` en cours de chemin ; * il n’est plus nécessaire d’instancier une variable à vide ; * c’est plus court ! Autre fait notable, le cas par défaut n’est plus obligatoire lorsque toutes les possibilités d’un `enum` sont traitées. Par précaution, en rajouter un peut protéger s’il y a un ajout dans l’énumération. Le mélange des syntaxes est aussi possible avec des risques d’erreurs comme le montre l’exemple suivant : ```java int i = switch (day) { case MONDAY -> { System.out.println("Monday"); // ERROR! Block doesn't contain a yield statement } default -> 1; }; i = switch (day) { case MONDAY, TUESDAY, WEDNESDAY: yield 0; default: System.out.println("Second half of the week"); // ERROR! Group doesn't contain a yield statement }; ``` Chacun se fera son avis sur ces nouvelles formes, car autant un `switch case` à l’ancienne est pénible à écrire, autant avec les nouvelles possibilités il va falloir s’accorder sur le style à suivre sur un projet. ## JDK Flight Recorder Event Streaming ## Dans Java 11, Oracle a libéré [Flight Recorder](https://openjdk.java.net/jeps/328) (FR) qui permet de suivre l’activité d’une application du sol au plafond, c’est‐à‐dire des appels processeur aux méthodes utilisées pour faire de l’affichage, en passant par le ramasse‐miettes et par le compilateur à la volée. Pour diverses explications, du code et des démos, allez voir cette [conférence](https://www.infoq.com/presentations/monitoring-jdk-jfr/) ou encore [cet article](https://blogs.oracle.com/javamagazine/java-flight-recorder-and-jfr-event-streaming-in-java-14). Toutefois, pour découvrir l’outil rapidement, il faut lancer votre application avec `java -XX:StartFlightRecording:filename=/tmp/monAppli.jfr -jar monAppli.jar`, interagir avec durant quelques instants et l’arrêter. Il est aussi possible de démarrer les enregistrements sur une application déjà en fonctionnement avec `jcmd MainClass JFR.start`. Ensuite, vous pouvez profiter d’un résumé des évènements enregistrés avec `$JAVA_HOME/bin/jfr summary /tmp/monAppli.jfr | less` ; pour une analyse plus poussée, [Java Mission Control](https://adoptopenjdk.net/jmc.html) est bien plus adapté. Le JDK Flight Recorder Event Streaming apporte la possibilité de profiter directement de ces mesures sans passer par la case écriture dans un fichier et lecture à partir de ce dernier. Ça peut sembler basique, mais ça ouvre de nombreuses possibilités pour monitorer de façon déportée différents services (un [exemple](https://github.com/gunnarmorling/jfr-custom-events) avec du Grafana et du Quarkus). ## Des NullPointerException plus explicites ## Dorénavant, les développeurs Java auront moins d’excuses pour passer de longs moments à décortiquer les NPE, car elles indiqueront quel objet est `null`. Cette fonctionnalité existe depuis 2006 dans le JDK de SAP, et la plus grande ouverture des contributions à Java a permis de la rendre disponible au plus grand nombre. Pour Java 14, il faudra activer l’option `-XX:+ShowCodeDetailsInExceptionMessages` afin d’en profiter et, à partir de Java 15, l’option sera activée par défaut. # Nouveautés en prévisualisation # ## Records ## La verbosité du langage n’est plus à démontrer et, pour alléger la charge, des efforts sont faits, notamment avec de l’inférence de type avec le mot clé `var` au moment de déclarer une variable. Les _records_ vont dans ce sens‐là, mais en plus ils permettent de transporter de la donnée de manière immutable. Voici un petit exemple de code : ```java public record Bouchot(String nom){} ``` C’est tout, une seule ligne pour créer un _record_ ! Derrière, le langage se débrouille pour générer les méthodes `equals()`, `toString()` et `hashCode()`. Pour accéder au nom d’un bouchot (que l’on aura déclaré comme ceci : `var monBouchot = new Bouchot("DLFP")`, il suffit de faire `monBouchot.nom()`. Un _record_ reste une classe Java, avec quelques limitations toutefois, il est donc possible de rajouter des contraintes sur le constructeur, par exemple refuser les `null` ou écrire votre propre méthode `toString()`, si la version générée ne vous convient pas. ```java public record Bouchot(String nom){ public Bouchot { if(null == nom){ throw new IllegalArgumentException("Crois‐tu qu’une moule puisse s’accrocher à null ?"); } } } ``` Une chose intéressante à savoir est que les _records_ ont été définis en prenant en compte le futur du langage aussi bien du côté développeur (types scellés, _pattern matching_ et déconstruction) que de la machinerie interne (_inline type_). Pour aller plus loin, je vous laisse lire cet [article](https://www.infoq.com/articles/java-14-feature-spotlight/). ## Pattern Matching instanceof ## Java est le dernier des principaux langages fonctionnant sur la JVM à ne pas implémenter le _pattern matching_. Pour cette première, il commence modestement en apportant un peu plus de légèreté syntaxique. ```java // Avant avec le cast if (obj instanceof Bouchot) { Bouchot b = (Bouchot) obj; var nom = b.nom(); } //Après if (obj instanceof Bouchot b) { var nom = b.nom(); } ``` L’étape suivante est de combiner le _pattern matching_ avec les _switch expressions_ et de pouvoir déconstruire les _records_. Tout le programme est détaillé dans la [JEP 375](https://openjdk.java.net/jeps/375) et en voici un avant‐goût : ```java record Point(int x, int y) {} if (obj instanceof Point(var a, var b)) { System.out.println(a+b); } ``` ## Outils d’empaquetage ## L’idéal de Java qui était, si je ne me trompe pas, compile ton application une seule fois et elle fonctionnera partout, semble ne plus trop être à l’ordre du jour. La démarche est plus, livre ton application avec les modules Java strictement nécessaires et, optionnellement, le JRE qui va avec. Le but étant la diminution de la taille des applications mais aussi l’amélioration de la réactivité et de la sécurité, car moins de code sera chargé et donc exposé. Comme d’habitude, les détails sont à lire dans la [JEP 343](https://openjdk.java.net/jeps/343). ## Les blocs de texte, seconde itération ## Après une première implémentation dans la version précédente de Java, en voici une nouvelle ([JEP 368](https://openjdk.java.net/jeps/368)). Le principe est d’avoir une solution élégante pour se débarrasser des concaténations sur plusieurs lignes, de se battre avec les échappements divers et variés et surtout améliorer la lisibilité. ```java String query = """ SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` WHERE `CITY` = 'INDIANAPOLIS' ORDER BY `EMP_ID`, `LAST_NAME`; """; ``` C’est aussi utilisable en combinaison avec d’autres bibliothèques, voici un exemple d’utilisation avec [JOOQ](https://blog.jooq.org/2020/03/05/using-java-13-text-blocks-for-plain-sql-with-jooq). Avec cette seconde version, viennent des caractères d’échappement des lignes pour jongler avec les lignes trop longues ou gérer plus finement les retours à la ligne. Dans l’exemple suivant toutes les lignes feront six caractères : ```java String colors = """ red \s green\s blue \s """; ``` # Les mises au placard et les départs # Ironie de l’histoire, l’architecture créée par la même société que le langage est dépréciée et ne sera rapidement plus supportée. Pour les rares qui ont encore du Solaris et du [SPARC](https://fr.wikipedia.org/wiki/Architecture_SPARC), c’est bientôt la fin pour faire tourner des machines virtuelles Java (JVM) modernes. Les détails sont présents dans la [JEP 362](https://openjdk.java.net/jeps/362). Même processus pour le ramasse‐miettes _Concurrent Mark Sweep_ dans le but de laisser plus de temps au développement des autres ramasse‐miettes, les détails dans la [JEP 291](https://openjdk.java.net/jeps/291). Suppression des outils Pack200, suite à leur placardisation dans Java 11, ils sont remplacés par les outils `jlink`, plus d’informations dans la [JEP 367](https://openjdk.java.net/jeps/367). # Dans les prochaines versions # La seconde version du _pattern matching_ de _instanceof_, les types scellés, la version définitive des blocs de texte. Je vous laisse regarder [cette diapo](https://github.com/forax/do-synthetic-methods-dream-of-electric-switch-expressions/blob/master/slideshow/chapter09-future.ipynb) de Rémi Forax (un contributeur d’OpenJDK). Pour une vision plus « sous le capot », Brian Goetz (un architecte du langage) a rédigé [deux articles](http://cr.openjdk.java.net/~briangoetz/valhalla/sov/01-background.html) sur les évolutions de Java.