<
Media
>
Article

Java 9, ce mal aimé

7 min
01
/
04
/
2025

Cet article n'a pas pour but de vous faire migrer vos applications vers Java 9, ni de faire l'apologie de Java 9, mais bien de montrer que cette version est méconnue et qu'elle a pu apporter énormément au langage et à notre quotidien. Elle a été précurseuse de certains sujets qui, aujourd'hui, font l'actualité de la communauté Java.

L'ensemble des javaistes considère Java 8 comme une révolution du langage Java. Beaucoup d'applications en production sont d'ailleurs encore basées sur cette version.  

Peu ont migré leurs applications de Java 8 à Java 9.  

Alors pourquoi écrire un article sur Java 9 me direz-vous ? Simplement parce que ce dernier a apporté des nouveautés radicales et annoncées comme quasi révolutionnaires pour Java : la modularisation, les JAR multi-releases et l'algorithme G1GC comme Garbage Collector par défaut.

Dans ce cas, pourquoi Java 9 n'a pas été aussi apprécié que Java 8 ? Connaissez-vous bien ce qu'il a réellement apporté au langage ?  

À travers cet article, nous verrons une liste non exhaustive des JEP (JDK Enhancement Proposal) qui vous feront peut-être revoir votre copie. Saviez-vous par exemple que Java 9 contient pas moins de 91 JEP !!

Condensé des meilleures JEP de Java 9

JEP 280: Indify String Concatenation

Avant Java 9, le compilateur convertissait chaque concaténation de chaînes <span class="css-span">String</span> en instructions StringBuilder. Avec cette approche, le code de concaténation était fixe et n'offrait pas de souplesse d'optimisation au moment de l'exécution. <span class="css-span">StringBuilder</span> s'est tellement ancré en nous aujourd'hui, que bon nombre de développeurs l'utilise pour concaténer les chaînes de caractères.

L'objectif de cette JEP était d'améliorer la concaténation de chaînes <span class="css-span">String</span> en utilisant <span class="css-span">invokedynamic</span> pour déléguer la concaténation à la factory <span class="css-span">StringConcatFactory</span>.

Pourquoi ? Afin de permettre à la JVM d’optimiser dynamiquement les opérations de concaténation selon le contexte d'exécution, tout en conservant la simplicité de l’opérateur <span class="css-span">+</span>.

Dans quel but ? En utilisant <span class="css-span">invokedynamic</span>, la JVM peut désormais adapter les concaténations pour améliorer les performances, réduire les allocations intermédiaires et ajuster le code en fonction de l'environnement d'exécution.

<span class="css-span">invokedynamic</span> ? Instruction introduite par Java7, elle permet au bytecode d’appeler une méthode qui peut être résolue dynamiquement au moment de l'exécution.

<span class="css-span">StringConcatFactory</span> ? C’est la fabrique qui choisit la meilleure stratégie de concaténation (comme <span class="css-span">StringBuilder</span>, <span class="css-span">StringBuffer</span>, des concaténations de tableaux de bytes ou encore des structures de buffer internes à la JVM) selon les conditions d’exécution (nombre et type d'opérandes).

Qu'est-ce que ça veut dire pour nous, développeurs ? Prenons l'exemple très simple suivant :

String result = "Hello, " + name + "!";

Depuis Java 9, le compilateur ne traduit plus ce code en une séquence d'instructions avec StringBuilder (comme c'était le cas avant Java 9). Au lieu de cela, le compilateur Java génère une instruction <span class="css-span">invokedynamic</span> dans le bytecode pour la concaténation de chaînes, qui ressemble à ceci : <span class="css-span">INVOKEDYNAMIC makeConcatWithConstants(...)</span>

Cette instruction demande à la JVM de décider au moment de l’exécution de la meilleure stratégie pour assembler les chaînes, en tenant compte du contexte exact. La JVM peut alors décider :

  • d'utiliser une instance de <span class="css-span">StringBuilder</span> si la concaténation est simple,
  • de combiner directement les chaînes en une seule opération, si elles sont constantes et peuvent être optimisées ainsi, réduisant alors l'empreinte mémoire,
  • d’optimiser la concaténation de manière plus efficace que <span class="css-span">StringBuilder</span> dans certains cas.

Au moment de l'exécution, quand la JVM lit l’instruction <span class="css-span">invokedynamic</span>, elle va déterminer dynamiquement (runtime) le meilleur moyen de réaliser l'opération de concaténation.  

Elle invoque ensuite une méthode de "bootstrap" (ou méthode "d’assistance"), capable d’identifier l’implémentation la plus performante pour la concaténation.  

Enfin, la JVM utilise cette stratégie pour toutes les concaténations similaires rencontrées, excepté si le contexte change, évidemment.

Attention cependant aux cas complexes :

  • En concaténant un très grand nombre de chaînes (l'agrégation de données par exemple), même si Java optimise les concaténations, <span class="css-span">StringBuilder</span> peut toujours être plus performant, car il permet de mieux gérer la mémoire et d'éviter les allocations répétées.
  • En construisant des chaînes de caractères à partir de nombreuses parties dynamiques, comme avec une utilisation de conditions ou d'opérations diverses, <span class="css-span">StringBuilder</span> peut offrir une lisibilité et une maintenabilité accrues.
  • En concaténant des chaînes de caractères au sein d'une boucle, <span class="css-span">StringBuilder</span> reste le plus efficace.

Pour résumer, vous pouvez généralement faire confiance à ces optimisations pour fonctionner efficacement. Cependant, pour des constructions plus complexes ou répétitives, <span class="css-span">StringBuilder</span> reste l'option à privilégier étant donné qu'elle est souvent plus performante.

JEP 254: Compact Strings

Cette JEP vise à optimiser la manière dont les chaînes de caractères <span class="css-span">String</span> sont représentées/stockées en mémoire.

Avant Java 9, les objets <span class="css-span">String</span> étaient représentés par des tableaux de caractères <span class="css-span">char[]</span>. Chaque caractère utilisait 2 octets (soit 16 bits) à cause de l'encodage utilisé : UTF-16.  

Même si vos chaînes de caractères ne contenaient que des caractères ASCII (donc 1 octet par caractère), le fait que l'encodage soit réalisé avec UTF-16 entrainait une consommation mémoire excessive et inutile.

Plusieurs changements ont donc été opérés :

  • La classe <span class="css-span">String</span> utilise désormais un tableau d'octets <span class="css-span">byte[]</span> au lieu d'un tableau de caractère <span class="css-span">char[]</span> pour stocker les données.
  • Un champ supplémentaire de 1 bit, appelé <span class="css-span">coder</span>, a été ajouté. Il est utilisé pour indiquer si la chaîne a été encodée en LATIN-1 (ou ASCII) ou en UTF-16, en prenant respectivement la valeur 0 ou 1.  

Si une chaîne contient uniquement des caractères ASCII (de 0 à 127), elle est alors stockée en utilisant 1 octet par caractère, sinon elle est stockée en UTF-16 comme auparavant.

Il y a évidemment des cas où Compact Strings ne s'applique pas. Par exemple, si votre chaîne contient des caractères non-ASCII, l'encodage se fera en UTF-16.

Vous l'aurez compris, cette JEP réduit la consommation mémoire des chaînes <span class="css-span">String</span>. Cette réduction de l'empreinte mémoire permet également un meilleur usage du cache CPU, pouvant améliorer les performances d'opérations sur les chaînes de caractères.

Moins de consommation mémoire et une réduction des objets volumineux en mémoire veut aussi dire moins de pression sur le Garbage Collector.

TIPS
Si votre application manipule beaucoup de chaînes de caractères (lecture de base de données, de fichiers...) et qu'elle n'a pas de contrainte en termes de latence ou de temps réel, il est conseillé d'activer l'option de la JVM de déduplication de <span class="css-span">String</span> (<span class="css-span">-XX:+UseStringDeduplication</span>) apportée par Java 8. Elle vous permettra de réduire encore l'empreinte mémoire de vos chaînes de caractères.  
Vous pouvez vérifier, lors de vos benchmarks, si cette option est réellement utile à votre application en affichant les statistiques sur cette déduplication via l'option <span class="css-span">-XX:+PrintStringDeduplicationStatistics</span>.

JEP 266: More Concurrency Updates

Introduites en Java 8, les CompletableFuture permettent de gérer des opérations asynchrones et non bloquantes (ie sans bloquer le thread principal).

Java 9 améliore les CompletableFuture en introduisant de nouvelles méthodes :

  • <span class="css-span">delayedExecutor</span> permet d'exécuter une tâche après un délai spécifié,
  • <span class="css-span">orTimeout</span> définit un délai au bout duquel une tâche échouera si elle n'est pas terminée,
  • <span class="css-span">completeOnTimeout</span> permet de définir une valeur par défaut qui sera utilisée si la tâche n’est pas complétée avant le délai spécifié.

JEP 269: Convenience Factory Methods for Collections

Java 9 introduit des méthodes de factory pour créer des collections immuables de façon concise. Celles-ci sont beaucoup plus lisibles et pratiques, notamment pour des listes (ou ensembles). On y retrouve <span class="css-span">List.of</span>, <span class="css-span">Set.of</span> et <span class="css-span">Map.of</span>.

List<String> names = List.of("Foo", "Boo", "Fooboo");
Set<Integer> numbers = Set.of(1, 2, 3);
Map<String, Integer> map = Map.of("one", 1, "two", 2);

En plus d'être immuable (vous ne pouvez ni ajouter, ni modifier, ni supprimer des éléments), la collection n'allouera uniquement que le nombre d'éléments passés, et elle ne sera donc pas initialisée avec une capacité par défaut (10 pour un <span class="css-span">ArrayList</span>, 16 pour une <span class="css-span">HashSet</span> et 16 pour une <span class="css-span">HashMap</span>). C'est également un gain en termes de consommation mémoire.

JEP 213: Milling Project Coin

Ajout de méthodes privées aux interfaces

Depuis Java 9, nous pouvons désormais définir des méthodes privées (ou privées statiques) dans les interfaces.

public interface MyCustomInterface {

    default void myPublicMethod() {
        privateHelper();
    }

    private void myPrivateHelper() {
        System.out.println("Helper method");
    }
}

A première vue, ça semblait être une bonne approche. Mais nous pouvons vite nous demander quel avantage celle-ci pouvait réellement nous procurer...  

La réponse était pourtant simple, cette fonctionnalité permet de factoriser du code commun aux méthodes <span class="css-span">default</span> de l'interface.  

Prenons l'exemple très simple d'une interface de calcul :

public interface Calculator {
    default int addAndDouble(int a, int b) {
        int sum = a + b;
        return sum * 2;
    }

    default int subtractAndDouble(int a, int b) {
        int difference = a - b;
        return difference * 2;
    }
}

Le code <span class="css-span">return ... * 2</span> est dupliqué dans les deux méthodes par défaut. Cette JEP nous permet de factoriser comme suit :

public interface Calculator {
    default int addAndDouble(int a, int b) {
        return doubleIt(a + b);
    }

    default int subtractAndDouble(int a, int b) {
        return doubleIt(a - b);
    }

    private int doubleIt(int value) {
        return value * 2;
    }
}

Amélioration du <span class="css-span">try-with-resources</span>

Vous le savez certainement, Java 7 a introduit la notion de <span class="css-span">try-with-resources</span> permettant de fermer automatiquement les ressources implémentant <span class="css-span">AutoCloseable</span>. Mais pour être fermée automatiquement, la ressource devait être déclarée dans le bloc <span class="css-span">try</span>.

Java 9 simplifie son utilisation en supprimant la déclaration d'une nouvelle variable locale au sein du bloc <span class="css-span">try</span>.  

Vous pouvez donc désormais déclarer une ressource en amont de votre <span class="css-span">try-with-resources</span>, celle-ci sera toujours fermée en sortie de bloc.

Avant Java 9 :

... // code
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    ... // code
}

Avec Java 9 :

BufferedReader br = new BufferedReader(new FileReader("file.txt"));
... // code
try (br) {
    ... // code
}

Inférence de type dans les classes anonymes

Depuis Java 9, l'inférence de type avec le diamant (<span class="css-span"><></span>) dans les classes anonymes est pris en charge.  

Jusqu'à Java 9, nous déclarions une classe anonyme comme suit :

Map<String, List<String>> myMap = new HashMap<String, List<String>>() {
    // Classe anonyme
};

Nous pouvons désormais la modifier en :

Map<String, List<String>> myMap = new HashMap<>() {
    // Classe anonyme
};

L'avantage est relativement faible, mais cette amélioration réduit quand même la verbosité du code, tout en maintenant une inférence de type correcte.

JEP 248: Make G1 the Default Garbage Collector

Le G1GC, ou "Garbage First Garbage Collector", devient le Garbage Collector par défaut.

Contrairement aux autres garbage collectors, G1GC n’est pas "en temps réel". Nous pouvons lui fixer des objectifs de performances spécifiques. Nous pouvons lui demander que les Stop-The-World ne dépassent pas x millisecondes dans un intervalle de temps donné de y millisecondes. Il fera alors de son mieux pour atteindre cet objectif avec une forte probabilité.

Pour en savoir plus au sujet du G1GC et des garbage collectors en général, n'hésitez pas à lire nos articles La Heap Java pour les nuls, mais pas que... et La Heap Java pour les nuls, mais pas que... Round 2.

JEP 238: Multi-Release JAR Files

Cette fonctionnalité permet de regrouper dans un seul JAR du code spécifique à différentes versions de Java. Cela facilite la compatibilité ascendante des bibliothèques et des frameworks. Par exemple, un JAR multi-releases peut contenir une classe compilée pour Java 8 et une version de cette même classe spécifique pour Java 9 et ultérieur.

"Génial !" me direz-vous, mais malgré un avenir très prometteur sur le papier, cette JEP a littéralement fait un flop chez les javaistes. Voyons pourquoi.

  • La gestion de versions spécifiques dans un seul JAR rend clairement le code plus difficile à maintenir. Il faut s'assurer que les différentes versions de classes fonctionnent correctement ensemble et que les bonnes versions sont utilisées au bon moment. Par exemple, si une librairie a des fonctionnalités spécifiques pour Java 9, 10 et 11, mais pas pour Java 8, il devient plus (voire très) compliqué de maintenir le code si un bug est introduit dans l'une des versions spécifiques, car il faut tester et corriger chaque version de la classe à travers différentes versions de Java.
  • La prise en charge dans nos outils de build, comme Maven ou Gradle, ou dans certains de nos environnements d'exécution Java peut être incomplète ou nécessiter des configurations supplémentaires, et donc rendre la configuration du build bien plus complexe.
  • L'ajout de différentes versions de classes pour différentes versions de Java entraîne une certaine redondance dans le code. Certes, ça augmente la taille des fichiers JAR, mais ça peut également avoir un impact sur nos performances, surtout si de nombreuses versions sont incluses pour différentes versions de Java. De plus, si les classes spécifiques à une version de Java sont peu utilisées par notre code, l'ajout de ces versions supplémentaires dans le JAR devient inutile. La maintenance de ce code devient aussi plus complexe pour nous, car les modifications doivent être réalisées dans plusieurs versions de la même classe.
  • Si une classe utilise une API spécifique de Java 9, mais qu'elle dépend également d'une API de Java 8 pour certaines opérations, le gérer dans un seul JAR peut devenir très complexe, et rendre les bugs difficiles à localiser et à diagnostiquer, et donc difficiles à reproduire.
  • On ne va pas se le cacher, plutôt que de se fier aux JAR multi-releases, nous préférons tous gérer la compatibilité ascendante de manière explicite via nos chers gestionnaires de dépendances (Maven, Gradle...), où les différentes versions d'une bibliothèque peuvent être configurées explicitement. Ce n'est pas simple, mais c'est gérable.
  • Et pour finir, l'un des principaux points négatifs de cette JEP est son absence d'utilisation par les frameworks et librairies les plus populaires... Si les grands noms des frameworks Java n'ont pas adhéré, ça n'a clairement pas poussé la communauté à s'y intéresser.

JEP 261: Module System

Son but était d’introduire un système modulaire pour le JDK et de rendre le langage Java modulaire. Cela a permis de structurer la plateforme Java en modules distincts, afin de favoriser une gestion plus fine des dépendances, de réduire la taille des applications et d'améliorer la sécurité et les performances. Des très bons points !

Pour modulariser nos modules Java au sein de notre application, chaque module Java est défini par un fichier <span class="css-span">module-info.java</span>, placé à la racine de celui-ci. Ce fichier permet de spécifier le nom du module, ses dépendances (<span class="css-span">requires</span>), et les paquets qu'il expose (<span class="css-span">exports</span>). Assez simple, avouons-le.

Cette JEP est, sans aucun doute, la plus importante de Java 9, mais aussi la plus boudée des développeurs. Elle est la JEP clé qui a posé les bases du système de modules Java, et elle fait partie du projet nommé Jigsaw.

Mais sa complexité, son manque de compatibilité ascendante (librairies tierces non compatibles avec cette modularisation), mais aussi sans doute le fait que nous ayons tous perçus cette évolution comme une surcouche inutile (par rapport à la simplicité d'un monolithe codé en Java 8), ont freiné, voire empêché, son adoption par nous, les javaistes.

Depuis, la modularisation monolithique est devenue un vrai sujet. La communauté parle de plus en plus de Clean Architecture (pour en savoir plus, il est recommandé de lire "Clean Architecture: A Craftman's Guide to Software Structure and Design", écrit par Robert C. Martin, communément appelé Oncle Bob), et même Spring s'est engouffré dans la brèche avec la librairie "Spring Modulith" (voir l'article Spring Modulith ou comment redonner vie à l'Architecture Monolithique).

JEP 295: Ahead-of-Time Compilation

La JEP 295 a été introduite par Java 9 afin de permettre la précompilation de code Java avant son exécution.  

Contrairement à la compilation Just-In-Time (JIT) qui se produit lors de l'exécution du programme (runtime), la compilation AOT permettait de compiler certains morceaux du code Java en code machine avant même que le programme ne soit lancé.

L’un des objectifs majeurs de cette JEP, expérimentale en Java 9, était de réduire le temps de démarrage des applications Java en se concentrant sur les classes et les méthodes peu (voire pas) dynamiques, afin de les rendre plus rapides à l'exécution, sans avoir besoin d'attendre que le compilateur JIT effectue ses optimisations.  

Etant donné que la JVM n'avait plus besoin, au runtime, de compiler les classes précompilées par AOT, l'empreinte mémoire était également plus faible.

Les résultats n'ont certes pas toujours été au rendez-vous, et la prise en charge des optimisations était encore partielle. Mais cette expérimentation a ouvert la voix à la communauté vers la construction d'images natives afin d'améliorer drastiquement les temps de démarrage et la consommation de ressources, CPU et RAM.

La JEP 483 fera partie de Java 24. Elle introduira une nouvelle approche pour le chargement et le linking des classes AOT. Contrairement à la JEP 295, elle ne reposera pas sur jaotc mais sur un système basé sur CDS. Cette évolution visera à réduire les temps de démarrage en liant et chargeant les classes de manière prédictive pendant une phase de « training » avant exécution​.

JEP 102: Process API Updates

A travers cette JEP, Java 9 a apporté des améliorations à l'API Process, afin de mieux interagir avec les processus système, avec des méthodes pour obtenir l’identifiant du processus (PID), surveiller l’état, gérer les I/O de manière non bloquante, etc.

// Crée un processus externe (par exemple, un simple "ping" à google)
ProcessBuilder processBuilder = new ProcessBuilder("ping", "-c", "4", "google.com");
Process process = processBuilder.start();

// Obtenir et tracer l'ID du processus
long pid = process.pid();
System.out.println("ID du processus (PID) : " + pid);

// Utilise onExit() pour obtenir un retour lorsqu'il se termine
process.onExit().thenAccept(p -> {
    try {
        // Vérifie le code de sortie du processus
        int exitCode = p.exitValue();
        if (exitCode == 0) {
            System.out.println("Le processus s'est terminé avec succès !");
        } else {
            System.out.println("Le processus a échoué avec le code de sortie : " + exitCode);
        }
    } catch (Exception e) {
        ... // Traitement de l'exception
    }
});

// code exécuté en parallèle du "ping"

La récupération du PID peut s'avérer utile si vous devez surveiller ou gérer un processus au niveau système, pour tuer le processus (en cas de freeze ou d'incident), ou pour un suivi dans des logs et/ou pour calculer des métriques (de performances).

Contrairement à <span class="css-span">process.waitFor()</span>, bloquant le thread principal jusqu'à ce que le processus se termine, l'utilisation de <span class="css-span">onExit()</span> permet au programme de rester réactif et d'exécuter d'autres tâches pendant que le processus externe est en cours.

JEP 222: JShell

JShell est un REPL (Read-Eval-Print Loop) qui permet d’exécuter du code Java ligne par ligne, sans avoir besoin de compiler des classes entières. C’est un excellent outil pour tester du code rapidement, explorer des APIs ou apprendre Java.

jshell>
int a = 10;
jshell>System.out.

println(a +5);

JEP 259: Stack-Walking API

Avant cette JEP, les méthodes existantes, comme <span class="css-span">Thread.currentThread().getStackTrace()</span>, étaient coûteuses en termes de performance, car elles renvoyaient toujours une copie complète du tableau de StackTraceElement. Même si vous ne vouliez qu'une partie de la pile, vous étiez obligé d'obtenir et de parcourir tout le tableau.  

Il n'y avait aucun moyen facile de filtrer les données sans parcourir manuellement tout le tableau.  

L'accès était limité aux informations statiques de chaque élément, comme le fichier, le numéro de ligne, le nom de la méthode, mais pas à des informations dynamiques ou spécifiques au contexte.

Cette nouvelle API permet donc de parcourir et d'interagir avec la pile d’appels de manière plus flexible et performante. Elle expose un Stream, que vous pouvez filtrer ou transformer facilement grâce aux outils de la programmation fonctionnelle (filter, map...).

StackWalker walker = StackWalker.getInstance();
walker.walk(stream -> 
    stream.filter(frame -> frame.getClassName().contains("MyClass"))
          .forEach(System.out::println));

Hors JEP

Amélioration de Optional

Java 9 a ajouté des méthodes à <span class="css-span">Optional</span> pour rendre le code plus concis :

  • <span class="css-span">ifPresentOrElse</span> exécute une action si une valeur est présente, sinon il exécute une action différente

    Optional<String> name = Optional.of("Cédric");
    name.ifPresentOrElse( System.out::println, () -> System.out.println("No value")); // ici affiche Cédric

  • <span class="css-span">or</span> fournit un autre "Optional" si le premier est vide,
  • <span class="css-span">stream</span> transforme "Optional" en un "Stream",
  • <span class="css-span">orElseThrow</span> sans paramètre permet de lever une exception de type <span class="css-span">NoSuchElementException</span> si aucune valeur n'est présente.

Les nouvelles méthodes de Optional, comme ifPresentOrElse, rendent le code plus lisible et fluide, mais il est bon de noter qu'elles peuvent introduire une légère surcharge en raison de la gestion des objets encapsulés. Pour des cas critiques en performance, des alternatives plus simples peuvent être préférables : une vérification conditionnelle directe, avec null, sera en effet plus rapide.

Enrichissement de l'API Stream

L’API Stream a été enrichie avec de nouvelles méthodes utiles.

  • <span class="css-span">takeWhile</span> et <span class="css-span">dropWhile</span> permettent de limiter les éléments d’un flux en fonction d'une condition :

List<Integer> numbers = List.of(1, 2, 3, 4, 5);
  numbers.stream()
         .takeWhile(n -> n < 4)
         .forEach(System.out::println); // Affiche 1, 2 et 3
   List<Integer> numbers = List.of(1, 3, 7, 12, 8, 5, 15);
   List<Integer> result = numbers.stream()
                                 .dropWhile(n -> n < 10)
                                 .toList(); // result contient 12, 8, 5 et 15

  • <span class="css-span">iterate</span> avec condition, génère un flux fini ou infini avec une condition :

   List<Integer> evenNumbers = Stream.iterate(0, n -> n <= 10, n -> n + 2)
                                     .toList(); // evenNumbers contient 0, 2, 4, 6, 8 et 10

  • <span class="css-span">ofNullable</span> crée un flux d'un élément ou un flux vide si l'élément est null :

        String nullableString = null;
        Stream<String> stream = Stream.ofNullable(nullableString); // stream est vide

        nullableString = "Hello, World!";
        stream = Stream.ofNullable(nullableString); // stream contient "Hello, World!"

Conclusion

Certaines améliorations apportées par Java 9, bien que souvent discrètes, simplifient le code, augmentent les performances, et offrent des possibilités modernes pour gérer les flux de données, les processus, et la concaténation de chaînes.  

Comme vous avez pu le remarquer, ces JEP sont nombreuses, et parfois même, vous les utilisez sans savoir qu'elles sont apparues avec Java 9.  

Elles méritent quasiment toutes d’être explorées, car beaucoup d'entre elles enrichissent le langage tout en réduisant le besoin d’écrire du code supplémentaire.

Le fait que Java 9 a été boudé par la communauté, celle-ci préférant migrer ses applications de Java 8 vers Java 11 ou Java 17, est principalement dû au fait que les JEP 261 (Modularisation) et 238 (Jar Multi-Releases) ont été les plus mises en avant, et considérées comme inutiles ou trop complexes par les développeurs.

Pour finir, vous avez pu découvrir que cette version de Java apporta de nombreuses JEP très précieuses, qui continuent de vivre, comme la "Concaténation de Strings", le "Compact Strings", le G1GC par défaut, l'API "StackWalker"...  

La JEP expérimentale "Compilation AOT" a été abandonnée, mais ses principes ont influencé des technologies modernes comme CDS, GraalVM et la future JEP 483, visant à réduire la consommation des ressources et à améliorer les performances.

No items found.
ça t’a plu ?
Partage ce contenu
Cédric

Cédric est un Architecte Logiciel, mais plutôt Backend et plutôt Java. Il aime toutes les technologies, surtout l'éco-système Spring, puisque Pivotal arrive toujours à sortir de nouvelles librairies et continue de surprendre la communauté. Mais bon, il en aime plein d'autres : l'architecture Monolithique Modulaire et le Domain Driven Design, Sonarqube et le Clean as You Code, les bases de données relationnelles... En dehors de son métier-passion, il déteste deux choses : le mois de janvier sans neige, et s'ennuyer. Les 2 sont d'ailleurs peut-être liées...

Retrouvez le sur Linkedin