TL;DR
- Java a sorti 17 versions majeures depuis Java 8. Le langage n'a plus rien a voir avec ce qu'il etait en 2014.
- Les features qui comptent : records, sealed classes, pattern matching, text blocks, virtual threads.
- Java 21 est le plus gros changement depuis Java 8 : virtual threads (Project Loom) change la donne pour la concurrence.
- Java 25 (LTS, septembre 2025) est la nouvelle baseline : Structured Concurrency, Scoped Values, startup 40% plus rapide.
- L'ecosysteme a explose : Spring Boot 4, GraalVM, Quarkus, Jakarta EE, et Kotlin qui pousse Java a s'ameliorer.
- Tu n'as pas besoin de tout apprendre d'un coup. Records + virtual threads = 80% de la valeur.
Java 8, 2014. La derniere version qu'on a vraiment apprise.
Lambdas, streams, Optional, la nouvelle API de dates. Pour beaucoup de devs Java en entreprise -- moi inclus -- c'est la derniere version qu'on a vraiment etudiee. On a appris les streams, on a commence a coller des .map() et des .filter() partout, et puis on est passes a autre chose. Le backlog n'allait pas se livrer tout seul.
Sauf que depuis 2014, Java a sorti 17 versions majeures. Et il s'est passe des choses. Des vraies choses. Pas des ajustements de surface ou des APIs obscures dont personne ne se sert. Le langage lui-meme a change. La facon dont on ecrit du Java en 2026 n'a plus rien a voir avec 2014.
Le probleme, c'est que dans beaucoup d'equipes enterprise -- Safran, CGI, Inetum, je connais bien le contexte -- on tourne sur Java 17 voire 21, mais on code encore comme en Java 8. On ne sait pas ce qu'on rate. Cet article, c'est le guide que j'aurais aime avoir pour rattraper 12 ans en une lecture.
Le nouveau rythme : une version tous les 6 mois
Avant de parler des features, il faut comprendre ce qui a change dans le processus.
Jusqu'a Java 9, Oracle sortait une version majeure tous les 3-4 ans. Java 6 en 2006. Java 7 en 2011. Java 8 en 2014. Ca veut dire des releases massives, des retards, et des features qui arrivent 5 ans trop tard.
En 2017, Java passe a un rythme de release tous les 6 mois. Septembre et mars. Chaque version a un numero. Plus de "big bang". Les features arrivent progressivement, souvent en preview d'abord, puis finalisees une ou deux versions plus tard.
Le systeme LTS (Long-Term Support) reste pour les entreprises qui veulent de la stabilite : Java 11 (2018), Java 17 (2021), Java 21 (2023), Java 25 (septembre 2025). Oracle et les distributions OpenJDK supportent ces versions pendant des annees.
En pratique, ca veut dire qu'on n'a plus besoin de tout suivre. On peut sauter de LTS en LTS et recuperer 3 ans de features d'un coup.
Java 9-11 (2017-2018) -- Le passage difficile
Java 9 : le module system (Jigsaw)
Java 9 a introduit le systeme de modules. L'idee : structurer le JDK et les applications en modules avec des dependances explicites. En theorie, c'etait propre. En pratique, ca a casse des choses. Des librairies ne marchaient plus. Des acces internes du JDK etaient soudainement interdits.
La plupart des equipes ont ignore les modules pour leur propre code. Et honnement, c'est encore le cas aujourd'hui. Mais Jigsaw a permis a Oracle de nettoyer les internes du JDK, ce qui a rendu possible les ameliorations des versions suivantes.
Java 10 : var
Simple mais divisif. L'inference de type locale.
// Avant
Map<String, List<Customer>> customersByCity = getCustomersByCity();
// Java 10+
var customersByCity = getCustomersByCity();
var ne fonctionne que pour les variables locales. Le type est infere a la compilation -- ce n'est pas du typage dynamique. C'est juste moins de bruit. Une fois qu'on s'y habitue, on ne revient plus en arriere.
Java 11 : le premier LTS post-Java 8
Java 11 est le "minimum vital" si tu upgrades depuis Java 8. Il apporte :
- Un HTTP Client moderne (fini
HttpURLConnectionet Apache HttpClient pour les cas simples) - L'execution de fichiers Java en une ligne :
java MonScript.java - Des methodes utilitaires sur
String:isBlank(),strip(),lines(),repeat()
C'est aussi la version ou Oracle a change son modele de licence. OpenJDK est devenu la reference pour la plupart des equipes.
Java 12-16 (2019-2021) -- Le langage se modernise
C'est la ou Java commence a changer fondamentalement. Quatre features majeures arrivent en preview puis se stabilisent.
Switch expressions (Java 14)
Fini le switch qui ne renvoie rien et qui oblige a mettre des break partout.
// Avant : le switch classique (verbose, error-prone)
String label;
switch (status) {
case ACTIVE:
label = "Actif";
break;
case INACTIVE:
label = "Inactif";
break;
default:
label = "Inconnu";
break;
}
// Java 14+ : switch expression
var label = switch (status) {
case ACTIVE -> "Actif";
case INACTIVE -> "Inactif";
default -> "Inconnu";
};
La fleche -> remplace le : et le break. Le switch renvoie une valeur. C'est plus sur (le compilateur verifie l'exhaustivite) et plus lisible.
Text blocks (Java 15)
Les chaines multi-lignes avec """. Fini les concatenations de \n pour du JSON, du SQL ou du HTML.
// Avant
String json = "{\n" +
" \"name\": \"Radnoumane\",\n" +
" \"role\": \"dev\"\n" +
"}";
// Java 15+
var json = """
{
"name": "Radnoumane",
"role": "dev"
}
""";
Ca a l'air anodin, mais au quotidien ca change la lisibilite de tout le code qui manipule du texte structure.
Records (Java 16)
La feature la plus impactante de cette periode. Les records, c'est des classes de donnees immutables en une ligne.
// Avant : 40+ lignes pour un simple DTO
public class UserDTO {
private final String name;
private final String email;
public UserDTO(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() { return name; }
public String getEmail() { return email; }
@Override
public boolean equals(Object o) { /* ... */ }
@Override
public int hashCode() { /* ... */ }
@Override
public String toString() { /* ... */ }
}
// Java 16+ : une ligne
record UserDTO(String name, String email) {}
Le constructeur, les accesseurs, equals(), hashCode(), toString() -- tout est genere automatiquement. Et comme c'est immutable par design, ca encourage de meilleures pratiques.
Pattern matching pour instanceof (Java 16)
Fini le cast apres le check.
// Avant
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// Java 16+
if (obj instanceof String s) {
System.out.println(s.length());
}
Ca parait mineur, mais multiplie par les centaines de instanceof dans un codebase enterprise, ca fait une vraie difference.
Java 17 (2021) -- Le grand LTS
Java 17, c'est la version ou toutes les features precedentes sont finalisees et stables. C'est le vrai point de depart si tu upgrades aujourd'hui.
Sealed classes
Les sealed classes restreignent quelles classes peuvent en heriter. Ca permet au compilateur de savoir que le type est fini, et donc de verifier l'exhaustivite.
sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double base, double height) implements Shape {}
Combine avec le pattern matching (qui arrive en 21), ca donne un systeme de types algebriques. Si tu viens de Kotlin ou Rust, tu connais le concept. C'est enorme pour modeliser des domaines metier.
Pourquoi Java 17 comme baseline
Presque tous les frameworks modernes exigent maintenant Java 17 minimum :
- Spring Boot 3.0+ (novembre 2022)
- Spring Boot 4.0 (2025)
- Quarkus 3.0+
- Jakarta EE 10+
Si ton projet est encore sur Java 11, tu ne peux deja plus utiliser les dernieres versions de Spring Boot. Java 17 est le plancher.
Java 21 (2023) -- La revolution
Si tu ne retiens qu'une version dans cet article, c'est celle-la. Java 21 est le plus gros changement depuis Java 8.
Virtual threads (Project Loom)
Pendant 25 ans, chaque thread Java etait mappe sur un thread OS. Ca veut dire que creer 10 000 threads concurrents, c'etait impraticable. On utilisait des thread pools avec 200-500 threads max, et des modeles reactifs (Spring WebFlux, CompletableFuture) pour contourner le probleme.
Les virtual threads changent tout. Ce sont des threads legers, geres par la JVM, pas par l'OS. On peut en creer des millions.
// Avant : thread pool avec 200 threads max
ExecutorService pool = Executors.newFixedThreadPool(200);
for (Request request : requests) {
pool.submit(() -> handleRequest(request));
}
// Java 21+ : un virtual thread par tache, des millions possibles
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (Request request : requests) {
executor.submit(() -> handleRequest(request));
}
}
Le code est quasiment identique. Mais les implications sont enormes :
- Plus besoin de code reactif pour la plupart des cas. Du code bloquant simple qui scale.
- Un thread par requete HTTP, comme au bon vieux temps, mais sans la limite de l'OS.
- Spring Boot 3.2+ supporte les virtual threads out-of-the-box avec une ligne de config :
spring.threads.virtual.enabled=true.
Netflix a migre ses services vers les virtual threads et a mesure une reduction significative de la latence et de l'utilisation memoire. C'est du reel, pas du marketing.
Pattern matching pour switch
Le pattern matching complete dans les switch. On peut matcher sur le type, destructurer des records, et avoir des guards.
static String describe(Shape shape) {
return switch (shape) {
case Circle c when c.radius() > 10 -> "Grand cercle de rayon " + c.radius();
case Circle c -> "Petit cercle";
case Rectangle r -> "Rectangle " + r.width() + "x" + r.height();
case Triangle t -> "Triangle";
};
}
Combine avec sealed classes et records, ca donne un systeme de pattern matching au niveau de ce que font Kotlin ou Scala. Le compilateur verifie que tous les cas sont couverts.
Sequenced Collections
Un ajout simple mais bienvenu. Les collections ordonnees (List, LinkedHashSet, LinkedHashMap) ont maintenant des methodes .getFirst(), .getLast(), .reversed(). Fini les list.get(list.size() - 1).
Java 24-25 (2025-2026) -- La maturite
Java 24 (mars 2025)
Java 24 corrige un probleme majeur des virtual threads : le synchronized pinning. Avant, un virtual thread dans un bloc synchronized bloquait le carrier thread OS. C'est corrige. Les virtual threads sont maintenant fiables dans tous les cas.
Autre ajout important : Project Leyden (AOT compilation pour le JDK). Les premieres optimisations arrivent avec un startup 40% plus rapide sur certaines applications. Java qui demarre vite, c'est nouveau.
Java 25 (septembre 2025, LTS)
Java 25 est le prochain LTS. C'est la nouvelle baseline pour les 3-4 prochaines annees.
Scoped Values (finalises) : une alternative aux ThreadLocal pour les virtual threads. Plus propre, plus performant, et concu pour le modele "un thread par requete".
static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();
ScopedValue.runWhere(CURRENT_USER, authenticatedUser, () -> {
// Tout le code dans ce scope a acces a CURRENT_USER.get()
processRequest();
});
Structured Concurrency (5eme preview) : gerer des taches concurrentes comme un bloc structure. Si une sous-tache echoue, les autres sont annulees automatiquement.
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Subtask<User> user = scope.fork(() -> findUser(id));
Subtask<Order> order = scope.fork(() -> findOrder(id));
scope.join().throwIfFailed();
return new UserOrder(user.get(), order.get());
}
Compact Object Headers : reduction de la taille des headers d'objets en memoire. Moins de RAM consommee, meilleures performances pour les applications qui creent beaucoup d'objets (c'est-a-dire toutes les applications Java).
L'ecosysteme qui a explose
Java le langage a change. Mais l'ecosysteme autour a aussi enormement evolue.
Spring Boot 2 -> 3 -> 4
Spring Boot 3 (novembre 2022) a ete une rupture : migration de javax.* vers jakarta.* (le namespace Jakarta EE), Java 17 minimum, support de la compilation native via GraalVM. Ca a casse la compatibilite avec beaucoup de librairies.
Spring Boot 4 (2025) passe a Java 25, integre nativement les virtual threads, et s'appuie sur Jakarta EE 11. C'est le framework enterprise Java de reference, et il avance vite.
GraalVM et la compilation native
GraalVM permet de compiler une application Java en binaire natif. Resultat : demarrage en millisecondes au lieu de secondes, et une empreinte memoire divisee par 5-10. C'est ideal pour les microservices et le serverless.
Le revers : la compilation native est lente, certaines librairies ne sont pas compatibles (reflexion, proxies), et le debugging est plus complexe. Oracle a aussi annonce qu'il retirait la Community Edition de GraalVM du JDK a terme, ce qui pousse vers des alternatives.
Quarkus et Micronaut
Deux frameworks cloud-native nes dans l'ere post-Spring :
- Quarkus (Red Hat) : concu pour GraalVM et les containers. Startup ultra-rapide, hot-reload en dev, extensions pour tout l'ecosysteme enterprise.
- Micronaut : compile-time dependency injection (pas de reflexion au runtime). Ideal pour les microservices et le serverless.
Est-ce que ca remplace Spring Boot ? Pour la grande majorite des projets enterprise, non. Mais pour du serverless ou des lambdas, ca vaut le coup d'oeil.
Jakarta EE (ex-Java EE)
En 2017, Oracle a transfere Java EE a la fondation Eclipse. Renomme Jakarta EE, le namespace est passe de javax.* a jakarta.*. C'est ce qui a force la migration dans Spring Boot 3.
Jakarta EE 10 et 11 continuent d'evoluer, mais l'ecosysteme s'est clairement deplace vers Spring Boot et les frameworks alternatifs pour l'innovation.
Kotlin : le rival qui pousse Java a s'ameliorer
Kotlin est devenu le langage par defaut sur Android et gagne du terrain cote backend. Beaucoup de features que Java a ajoutees (records, sealed classes, pattern matching, text blocks) existaient deja en Kotlin.
La concurrence est saine. Elle a force Java a evoluer plus vite et a prendre des decisions qu'Oracle n'aurait jamais prises il y a 10 ans.
Ce que tu rates si tu codes encore comme en Java 8
Un comparatif concret, cote a cote.
Modeliser des donnees :
// Java 8 : 40 lignes pour un DTO
public class UserDTO {
private final String name;
private final String email;
public UserDTO(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() { return name; }
public String getEmail() { return email; }
// + equals, hashCode, toString...
}
// Java 16+ : 1 ligne
record UserDTO(String name, String email) {}
Verifier un type :
// Java 8
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// Java 16+
if (obj instanceof String s) {
System.out.println(s.length());
}
Gerer la concurrence :
// Java 8 : thread pool avec limite fixe
ExecutorService pool = Executors.newFixedThreadPool(200);
// Java 21+ : virtual threads, des millions possibles
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> handleRequest(request));
}
Ecrire du JSON/SQL inline :
// Java 8
String query = "SELECT u.name, u.email\n" +
"FROM users u\n" +
"WHERE u.active = true\n" +
"ORDER BY u.name";
// Java 15+
var query = """
SELECT u.name, u.email
FROM users u
WHERE u.active = true
ORDER BY u.name
""";
Brancher sur un type :
// Java 8 : if/else instanceof + cast
if (shape instanceof Circle) {
Circle c = (Circle) shape;
return Math.PI * c.getRadius() * c.getRadius();
} else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle) shape;
return r.getWidth() * r.getHeight();
}
// Java 21+ : pattern matching switch
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> 0.5 * t.base() * t.height();
};
Multiplie ca par des milliers de fichiers dans un codebase enterprise. Le code moderne est plus court, plus sur, et plus lisible.
Par ou commencer si tu es bloque a Java 8
Pas besoin de tout apprendre d'un coup. Voici un chemin pragmatique.
Etape 1 : Upgrade vers Java 21. C'est le LTS actuel avec les virtual threads. Spring Boot 3.2+ le supporte. C'est ta cible immediate.
Etape 2 : Apprends records, sealed classes, et pattern matching. Ces trois features changent ta facon de modeliser les donnees et d'ecrire de la logique metier. Commence par convertir tes DTOs en records.
Etape 3 : Essaie les virtual threads sur un vrai projet. Active-les dans Spring Boot (spring.threads.virtual.enabled=true) et mesure la difference. Sur un service IO-bound, les resultats sont souvent spectaculaires.
Etape 4 : Vise Java 25 pour la baseline future. C'est le prochain LTS (septembre 2025). Structured Concurrency et Scoped Values vont devenir la norme pour ecrire du code concurrent propre.
La regle simple : records + virtual threads = 80% de la valeur. Le reste viendra naturellement.
Si tu veux aussi rattraper ton retard en IA, j'ai écrit une série complète sur le sujet.
Ressources
Pour aller plus loin :
- JDK Release Notes -- les notes de release officielles de chaque version
- Java Almanac -- comparaison visuelle entre les versions, feature par feature
- Baeldung Java 25 Features -- guide pratique des nouveautes Java 25
- Inside Java -- le blog officiel Oracle, avec les JEPs expliquees
- State of Java 2026 -- etat des lieux de l'ecosysteme
- Netflix Virtual Threads case study -- retour d'experience production sur Project Loom