
tour d'horizon des nouveautés
Après l'arrivée de Java 8 et ses nombreuses fonctionnalités en 2014, Java 9 pointe enfin le bout de son nez ce 21 septembre 2017. Java 9 inclut plus de 80 nouveautés toutes décrites dans un ensemble de JEP (Java Enhancement Proposal) disponibles à cette adresse : http://openjdk.java.net/projects/jdk9/.
À travers cette annonce, l'équipe Java de Developpez.com va vous donner un aperçu de ce qu’apporte le JDK 9 ; voici quelques-unes de ces nouveautés qui pourraient avoir un impact sur votre façon de programmer avec Java. Nous finirons par nos avis personnels respectifs. Ensuite cela sera votre tour ;-)
La modularisation via le projet Jigsaw
La modularisation annoncée depuis de nombreuses années, plusieurs fois repoussée, est LA grande nouveauté de Java 9. Elle a été décrite principalement dans la JEP 201. D’autres JEP sont liées à celle-ci tant le projet de modularisation est important. L’objectif principal du système des modules est de fournir un JDK qui puisse être structuré et de pouvoir charger seulement les modules nécessaires. Les applications du domaine de l’Internet des Objets (IOT en anglais) sont très demandeuses, car les systèmes hôtes sont généralement limités en ressources matérielles (mémoire, CPU…). Les développeurs Java pourront donc spécifier les modules du JDK et des bibliothèques tierces qui sont requis par leur application.
Sur le plan théorique, le système de module apporte également de nombreux autres avantages :
- une plateforme plus facilement évolutive et maintenable ;
- des gains en termes de performance et d'exécution puisque seuls les modules nécessaires sont chargés ;
- des gains en termes de sécurité, car le principe modulaire permet de fournir le juste assez nécessaire au système. De plus, l’utilisation d’API privées est impossible si celles-ci ne sont pas explicitement exportées.
Comment ça fonctionne ?
Pour considérer une application tirant parti du système de modules, un fichier module-info.java est requis à la racine de votre projet. Un exemple de contenu de fichier module-info.java est proposé ci-dessous :
Code : | Sélectionner tout |
1 2 3 4 | module com.developpez { requires java.sql; export fr.developpez.com.services; } |
Les personnes ayant une connaissance de OSGi ne seront pas surprises par la syntaxe hormis l’absence de numéro de version. En effet dans cette première version, Jigsaw a fait l’impasse sur les versions. Cet aspect est délégué aux outils de build comme Maven ou Gradle.
Bien sûr, comme toute grosse nouveauté, il y a quelques problèmes. On peut citer par exemple l’utilisation de la méthode setAccessible(boolean) qui permet d’accéder à des champs privés par réflexion. Cette méthode ne fonctionnera plus pour accéder à un champ privé contenu dans un module pour des raisons de sécurité et vous obtiendrez donc une belle exception de type : IllegalAccessError. Pour résoudre cela, il faudra « ouvrir » le module en utilisant le mot clé open sur le package ou plus globalement sur le module (voir ci-dessous).
Code : | Sélectionner tout |
1 2 3 4 | module fr.developpez.com { requires java.sql; opens fr.developpez.com.services; } |
Code : | Sélectionner tout |
1 2 3 4 | open module fr.developpez.com { requires java.sql; exports fr.developpez.com.services; } |
Les outils ?
Au niveau des outils, il y a eu également des changements. Les commandes java et javac disposent naturellement de paramètres spécifiques pour prendre en compte le système de module. L’outil jlink (JEP 282) permet d'assembler plusieurs modules Java entre eux en tenant compte de leurs dépendances. Le résultat consiste en une image spécifique du runtime Java (JDK ou JRE) en intégrant son application. Enfin, sans être exhaustif, l’outil jdeps permet de connaître les modules dont dépend votre projet.
Fabriques pour les collections
La nouvelle version de Java 9 apporte de gros changements au niveau des API dédiées aux collections. Des méthodes statiques ont été ajoutées sur les interfaces de List, Set et Map pour initialiser des collections. Par ailleurs, les objets créés sont immutables (les attributs les contenant ne sont pas modifiables). L'objectif visé par cette amélioration décrite dans la JEP 269 étant bien sûr la création de petites collections et d'éviter une lourdeur syntaxique.
Avant Java 9, nous étions obligés de faire cela :
Code : | Sélectionner tout |
1 2 3 4 5 | List<String> myList = new ArrayList<String>(); myList.add("Developpez.com"); myList.add("Aime"); myList.add("Java"); myList = Collections.unmodifiableList(myList); |
Avec Java 9, la création devient plus simple.
Code : | Sélectionner tout |
List<String> newList = List.of("Developpez.com", "Aime", "Java")
Cette amélioration, décrite dans la JEP 102 permet à Java de mieux coexister avec le système. Initialement le développeur Java utilisait l’API Runtime.getRuntime().exec() puis avec Java 5 est apparue l’API ProcessBuilder. Malheureusement, il n’était pas possible de connaître le PID du processus courant, connaître les sous-processus, détruire des processus ou obtenir d’autres informations comme les paramètres d’exécution. Avec Java 9, les choses ont évolué dans le bon sens avec des nouvelles classes comme ProcessHandle et des ajouts dans la classe Process.
Pour récupérer le processus courant :
Code : | Sélectionner tout |
System.out.println(ProcessHandle.current())
Code : | Sélectionner tout |
1 2 3 4 | ProcessHandle.allProcesses().forEach(p -> System.out.println(p.getPid() + " " + p.info().commandLine())); 1 Optional[/usr/lib/jvm/java-9-openjdk-amd64/bin/jshell -v] 45 Optional[/usr/lib/jvm/java-9-openjdk-amd64/bin/java -agentlib:... jdk.jshell.execution.RemoteExecutionControl 34065] 137 Optional[/usr/bin/sleep 1h] |
Le format du fichier JAR évolue. Celui-ci permet de gérer plusieurs implémentations d'une même classe au sein d'une archive unique. Avant Java 9, il était donc impossible de gérer plusieurs versions d’une même bibliothèque au sein d’une même archive.
Il était important d'apporter une solution pour assurer la compatibilité descendante, car Java 9 intègre de nouvelles API permettant de coder différemment . À l'exécution, la bonne version de la classe sera chargée automatiquement en fonction de la version de Java utilisé. Cette solution est décrite dans la JEP 238, elle est appelée Multi-Release JAR (MR JAR pour les intimes).
Si on considère deux classes Foo et Bar. La seconde contient deux implémentations une pour Java 9 et une autre pour toutes les versions antérieures à Java 9. La structure du JAR sera la suivante :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 | JAR root - Foo.class - Bar.class + META-INF - MANIFEST.MF + versions + 9 - Bar.class |
Comme on peut constater la racine (JAR root) n'évolue pas et Foo.class et Bar.class seront utilisées par toutes les versions de Java ne supportant pas MR JAR. Au contraire Foo.class et Bar.class localisée dans META-INF/versions/9/Bar.class seront utilisées pour la version 9 de Java.
Cette fonctionnalité a demandé des améliorations au niveau des outils de compilation et d'analyse. Les outils du JDK (javac, javap, jdeps...) ont été bien entendu impactés. Les outils de build comme Maven ou Gradle ont dû s'adapter pour la construction de cette nouvelle structure de JAR. Sur le papier tout fonctionne pour preuve dans ce dépôt GIT où des tests ont été réalisés.
Un shell Java : REPL jShell
De nombreux langages sont actuellement très populaires grâce à leur simplicité pour l’apprentissage ; à titre d’exemple le langage Python. Cette simplicité est en partie due à la présence d’une implémentation appelée REPL (Read Evaluate Print Loop). Grâce à ce mode de fonctionnement basé sur une boucle, l’interpréteur :
- Lit une expression (le R pour Read) ;
- Évalue une expression (le E pour Evaluate) ;
- Imprime sur la sortie standard (le P pour Print) ;
- Recommence (le L pour Loop).
Pour pallier ce manque, la version Java 9 offre un REPL appelé JShell (JEP 222) permettant une programmation interactive. JShell interprète directement des expressions sans avoir besoin qu’elles soient enveloppées dans une classe ou une méthode.
Outre l’aspect apprentissage, JShell pourra être utilisé pour tester du code rapidement en quelques lignes de code. Par exemple, vérifier si un service web est présent ou tester des agents de placement pour JavaFX. Il est également prévu de pouvoir intégrer JShell directement dans du code Java. On peut même envisager une alternative aux bons vieux scripts Bash et pourquoi pas des langages de script de la JVM comme Groovy.
Meilleure gestion du deprecated
L’annotation @Deprecated a été étoffée par deux attributs : l’un de type String since et l’autre de type boolean forRemoval (JEP 277). L’attribut since permet de préciser à partir de quand l’API a été annotée par @Deprecated et forRemoval précise que l’API en question risque d’être supprimée. Nous montrons ci-dessous un exemple de classe qui précise que cette API a été annotée @Deprecated depuis la version 2.5 et qu’elle n’est pas prévue pour être supprimée.
Code : | Sélectionner tout |
1 2 3 4 | @Deprecated(since="2.5" forRemoval=false) public class MaClassAMoi { … } |
La JEP 265 a permis l’intégration d’un nouveau moteur de rendu Marlin permettant aux boîtes à outils Java (Java2D et JavaFX) d'être plus rapides. Précédemment les moteurs de rendu Pisces et Ductus étaient utilisés (Oracle JDK). Comme le moteur de rendu Marlin surpasse en termes de performance ces deux moteurs historiques (2006 et 1998), l'équipe de l'OpenJDK 2D a décidé de l'utiliser par défaut dans l'OpenJDK 9 et Oracle de son côté a fait de même pour Oracle JDK9 pour se débarrasser à terme de Ductus.
Sur le graphique ci-dessous, on remarque que les résultats obtenus par le moteur de rendu Marlin sont toujours plus efficaces que les autres rendus. On atteint parfois des ratios de l'ordre de 650 %.
MarlinFX a été finalement intégré en décembre 2016 (à la dernière minute), mais il reste désactivé par défaut dans JDK 9 (Java Pisces ou Native Pisces restent utilisés). L’équipe Java de Developpez.com a pu réaliser une interview de Laurent Bourgès, l’auteur principal de cette fonctionnalité : https://java.developpez.com/interview/laurent-bourges/
Améliorations en vrac
Les nouveautés de Java 9 sont nombreuses. Nous aurions aussi pu citer les points suivants :
- Stream : de nouvelles méthodes ont été ajoutées dans les classes Stream et Collectors ;
- Concurrence (JEP 266) : Java 9 est désormais un langage réactif dans le sens où une implémentation des Reactive Streams a été proposée. La nouvelle classe Flow propose trois interfaces intégrées pour le producteur (Publisher), consommateur (Subscriber) et une dernière pour la connexion entre le producteur et le consommateur ;
- une nouvelle JavaDoc estampillée HTML 5 avec la possibilité de rechercher du contenu dans une zone de texte. C’est déjà une grosse évolution. Malheureusement, la recherche fulltext n’existe pas. Par ailleurs, les frames oldschool sont toujours présentes ;
- un vrai client HTTP/2 (JEP 110) ;
- G1, le garbage collector par défaut (JEP 248). Le garbage collector G1 est par défaut sur les architectures 32 et 64 bits. Il remplacera Parallel GC avec une approche plus intéressante pour les utilisateurs, car il diminuera les latences et son impact sur les ressources ;
- Milling Project Coin (JEP 213). Ce projet a trait à de nombreuses évolutions de la syntaxe de Java. On notera la possibilité d’avoir des méthodes privées dans les interfaces afin de mutualiser du code utilisé dans les méthodes par défaut. On notera aussi la possibilité d’utiliser des variables finales dans le bloc Try-With-Resources ;
- meilleure performance pour les chaînes de caractères proposées dans JEP 254, JEP 250 et JEP 280 ;
- InputStream : trois nouvelles méthodes utilitaires ont été ajoutées dans la classe InputStream. readAllBytes() pour lire tout un flux, readNBytes() pour lire une portion d'un flux et transferTo() pour directement envoyer un flux d'entrée vers un flux de sortie.
Les avis
Nous avons demandé aux membres de l’équipe Java de donner leur avis concernant cette nouvelle version de Java. Que pensent-ils de cette version, quelles nouveautés ont-ils préférées et celles qu'ils...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.