logo le blog invivoo blanc

Après Java 8, les nouveautés de Java 9

20 juin 2018 | Java | 0 comments

Trois ans après la sortie de Java 8, Java 9 a finalement vu le jour. Avec plus de 80 nouveautés, disponibles à cette adresse : http://openjdk.java.net/projects/jdk9/. (C’est une version très riche en contenu.)

A travers cet article vous aurez un résumé des principales nouveautés qu’apportent cette version.

Petit récapitulatif sur Java 8

« Java 8 made Java great again ? » Grâce à Java 8, Java est repassé “langage de l’année” en 2015 d’après l’index TIOBE. Il ne l’avait pas été depuis 2005.

tiobe capturing

Cette version a apporté un grand nombre de nouveautés et de bouleversements de la façon dont nous programmons en Java, en voici une liste :

  • Les expressions lambda,
  • Les références de méthodes,
  • La programmation fonctionnelle,
  • L’API Stream et Collector,
  • L’API Date & Time,
  • La classe Optional,
  • Les CompletableFuture,
  • La Permgen (Permanent Generation) remplacée par le Metaspace,
  • Les méthodes statiques et par défaut sur les interfaces.

Sans parler de JavaFX, bibliothèque graphique maintenue par Oracle en remplacement de Swing et de AWT, qui a aussi été grandement mis à jour avec l’arrivée de cette version.

Les nouveautés de Java 9

Java 9 a été la version la plus controversée. En effet, c’est la première fois que le comité exécutif du JCP, « Java Community Process » (organisation qui coordonne l’évolution du langage Java), vote non à sa sortie. Cependant, elle a quand même été diffusée en septembre 2017.

Quelques à priori sur Java 9

On entend beaucoup de chose sur Java 9, ici nous allons démentir quelques à priori :

Ø  « Le classPath est remplacé par le module-path » : Non, les deux cohabitent.

Ø  « Le code de l’application doit être modulaire » : C’est l’objectif à terme, mais aujourd’hui il est tout à fait possible d’utiliser du code non modulaire.

Ø  « sun.misc.Unsafe est retiré » : Elle ne l’est pas, c’est un objectif, mais il manque encore des solutions de remplacement de certaines fonctionnalités.

Ø  « La majorité du code existant n’aura pas besoin d’être modifié » : Oui, il y aura des modifications à apporter, mais la majorité du code restera le même.

Les avantages de Java 9

Même si le comité a refusé sa sortie, Java 9 a de nombreux avantages. En voici quelques uns :

    L’amélioration de la syntaxe
  • Des variables effectivement finales dans « try-with-resources » :

Les variables finales et effectivement finales peuvent être placées dans des blocs « try-with-resources », à partir de Java 9. Cela vous donnera plus d’options pour la gestion automatique des ressources.

En java 7 avec l’ajout du bloc « try-with-resources » la syntaxe s’écrivait ainsi :

try (BufferedReader reader1 = new BufferedReader(new FileReader("fichier1.txt"));
     BufferedReader reader2 = new BufferedReader(new FileReader("fichier2.txt"));
     BufferedReader reader3 = new BufferedReader(new FileReader("fichier3.txt"))) {
    
    System.out.println(reader1.readLine());
    System.out.println(reader2.readLine());
    System.out.println(reader3.readLine());
}

Maintenant, en Java 9, il est possible de déclarer les ressources « Closeable » à l’extérieur du bloc try si elles sont finales ou effectivement finales. Il est également possible pour faciliter la lisibilité de créer des méthodes utilitaires pour l’instanciation des ressources, dans le bloc de code ci-dessous en Java 9 pour instancier notre reader 1 nous avons fait appel à une méthode utilitaire. Les deux autres readers sont, quant à eux, directement instanciés mais dans le bloc try-with-resources, étant donné que les readers sont finaux il suffit de les lister dans le try pour qu’ils se ferment automatiquement dans le finally :

BufferedReader reader1 = getNewReader();
BufferedReader reader2 = new BufferedReader(new FileReader("fichier2.txt"));
BufferedReader reader3 = new BufferedReader(new FileReader("fichier3.txt"));

try (reader1; reader2; reader3) {
    System.out.println(reader1.readLine());
    System.out.println(reader2.readLine());
    System.out.println(reader3.readLine());
}
  • Des méthodes « private » dans les interfaces :

Après les méthodes statiques et défauts dans Java 8, Java 9 ajoute les méthodes privées dans les interfaces. Les deux principaux avantages à ça sont :

–   Permet de faciliter l’encapsulation et éviter de dupliquer certaines parties du code,

–   Exposer uniquement les méthodes souhaitées.

  • L’opérateur diamant dans les classes anonymes internes :

L’opérateur diamant peut maintenant être utilisé dans les classes anonymes internes :

UnaryOperator<Integer> increment = new UnaryOperator<>() {
    @Override
    public Integer apply(Integer integer) {
        return integer + 1;
    }
};

System.out.println(increment.apply(1));

Avec ce code vous n’aurez plus l’erreur de compilation « ‘<>‘ cannot be used with anonymous classes. » et votre code sera plus lisible.

  • L’annotation @SafeVarargs est maintenant utilisable sur les méthodes d’instances privées :

Cette annotation permet de définir que le corps de la méthode annotée ou du constructeur n’effectue pas d’opérations potentiellement dangereuses sur son paramètre varargs. Désormais l’annotation est utilisable sur les méthodes d’instances privées.

 

    API et outils
  • Des fabriques pour des collections immutables :

– List.of(),

– Set.of(),

– Map.of().

En Java 8 une liste immutable aurait été créée de cette manière :

List<String> chiffres = Arrays.asList("1", "2", "3", "4");

chiffres = Collections.unmodifiableList(chiffres);

Dorénavant en Java 9 il suffit simplement de faire appel à la méthode .of de l’interface List :

List<String> chiffresImmutables = List.of("1", "2", "3", "4");

L’utilisation est similaire pour l’API Set.of() et Map.of().

  • L’ajout d’API sur la classe Process qui permettent :

– d’identifier les processus directs enfant ou descendant,

– d’obtenir le PID de ce Processus,

– de retourner une « snapshot » d’informations sur ce Processus,

– d’obtenir un « completable future » pour recevoir une notification asynchrone.

  • L’ajout de Reactive stream avec l’API Flow qui permet de standardiser le pattern reactive dans 4 interfaces :

– Publisher,

– Subscriber,

– Subscription,

– Processor.

  • L’API VarHandle qui fournit un accès en écriture et en lecture aux variables, en quelque sorte une référence typée vers les variables d’une classe, l’objectif ici est de remplacer certaines fonctionnalités de l’API Unsafe.

Voici un exemple de son utilisation sur une variable :

Private static class Arbre {
    float taille;
}

static final VarHandle VH_ARBRE_FIELD_TAILLE;

static {
    try {
        VH_ARBRE_FIELD_TAILLE = MethodHandles.lookup()
                                             .in(Arbre.class)
                                             .findVarHandle(Arbre.class, "taille", float.class);
    } catch (Exception e) {
        throw new Error(e);
    }
}

Il est ainsi possible de récupérer la valeur d’un attribut et de la modifier sans passer par l’API Unsafe :

Arbre arbre = new Arbre();
arbre.taille = 3.4f;

System.out.println(VH_ARBRE_FIELD_TAILLE.get(arbre));
VH_ARBRE_FIELD_TAILLE.set(arbre, 4.0f);
System.out.println(VH_ARBRE_FIELD_TAILLE.get(arbre));

Résultat obtenu :

3.4

4.0

Nous avons vu dans l’exemple l’utilisation en lecture en utilisant le « get » et en écriture avec le « set », il existe aussi l’écriture conditionnée par une valeur avec l’appel de la méthode « compareAndSet » :

Si la valeur passée en paramètre correspond à la valeur de l’attribut elle sera mise à jour avec la valeur passée en troisième paramètre :

VH_ARBRE_FIELD_TAILLE.compareAndSet(arbre, 4f, 2f);
System.out.println(VH_ARBRE_FIELD_TAILLE.get(arbre));

 

Les nouveaux outils :

  • JShell est un outil de type REPL en ligne de commande qui permet d’exécuter du code Java de manière simplifiée, un peu comme on le ferait avec du python.
  • Jlink est également un outil en ligne de commande et qui permet de créer son propre JRE allégé et qui ne contient que les modules que nous souhaitons utiliser.
  • Jdeprscan qui scanne les classes pour vérifier l’utilisation d’API dépréciées de Java.

 

    L’amélioration de la JVM

Sur chaque version nous avons des améliorations de la JVM, avec sur cette version globalement de meilleures performances et ce notamment grâce à plusieurs optimisations :

  • Compact String

Nous ne sommes plus sur un tableau de char, mais sur un tableau de byte, la consommation de CPU est augmentée, mais la taille des chaînes de caractères est grandement réduite.

  • Concaténation des chaînes avec InvokeDynamic

Le byte-code de concaténation a été remplacé par un appel InvokeDynamic ainsi qu’une méthode bootstrap qui va générer l’appel de concat.

  • G1 utilisé comme Garbage Collector par défaut

De nombreuses améliorations ont été apportées au G1 dans la JDK 8 et ses mises à jour, et d’autres améliorations ont été apportées dans la JDK 9. L’introduction du déchargement de classes simultanées (JEP 156) dans le JDK 8u40 a fait du G1 un garbage collector complet, prêt à être utilisé par défaut.

  • Segmentation du code du cache

Le code compilé a été réparti dans des caches séparés, chaque segment de cache correspond à un type particulier.

  • Unification du système de log de la JVM
    Les modules

Les modules sont perçus comme contraignants avec une impression de perte de liberté en comparaison avec ce qui est fait depuis plus de 20 ans.

Voici un petit récapitulatif de certaines contraintes et avantages apportés par ce nouveau design :

Contraintes Avantages
Plus d’accès par défaut aux classes publiques d’un module Encapsulation forte qui améliore la sécurité et la maintenabilité
Plus d’introspection par défaut sur les classes d’un module Configuration fiable qui réduit les problèmes du « classpath hell »
Plus de split packages Remettre de l’ordre dans le design des livrables
Plus de dépendances circulaires Remettre de l’ordre dans les dépendances
Définir les dépendances dans les module-info et les outils de build Remettre de l’ordre dans les API utilisées

Maintenant attaquons nous aux types de modules, nous en avons plusieurs :

  • Les platform modules qui contiennent les modules du JRE,
  • Les App Named Modules avec les Jar modulaire dans le module path,
  • L’Unnamed module, un seul module qui contient notamment les jars du class path, il a la particularité d’avoir accès à :

–   Tous les packages exportés par tous les autres modules disponibles dans le module-path,

–  Tous les jars du classpath (tous les autres types présents dans cet unnamed module).

  • Les Automatic modules : les modules automatiques voient tous leurs types publics exportés. Un module utilisant un module automatique peut donc utiliser n’importe quel type public, de la même manière qu’en java 8 nous utilisions un jar.

Pour pouvoir profiter de toutes ces nouveautés et embarquer dans le cycle de release beaucoup plus court proposé par Oracle, il faudra obligatoirement mettre à jour les versions de nos jdk… Vous pourrez retrouver toutes les informations qu’il vous faut dans notre prochain article : Un incontournable : la migration vers Java 9.

 

Liens utiles :

Nouveautés Java 9 par Oracle : https://www.oracle.com/corporate/features/jdk9-new-developer-features.html

Conférence Devoxx liée à l’article : https://www.youtube.com/watch?v=dYubeLiObqY