
Guide de Migration Java 8 → Java 20
Guide de Migration Java 8 → Java 20
Depuis la sortie de Java 8 en 2014, le langage Java a considérablement évolué. Java 20, publié en 2023, marque une étape importante avec des fonctionnalités mature et d'autres en mode "preview". Ce guide vous accompagne dans la compréhension des principales évolutions, du plus simple au plus avancé.
Contexte : Java 8, un point de départ majeur
Java 8 (2014) a révolutionné le langage avec :
- Lambda expressions — Fonctions anonymes pour le style fonctionnel
- Stream API — Traitement fonctionnel des collections
- Optional — Gestion explicite des valeurs nulles
- Default methods — Méthodes par défaut dans les interfaces
- Date API (java.time) — Remplacement de Date/Calendar
Java 20 (2023) construit sur cette base avec des fonctionnalités plus subtiles mais puissantes.
1. Records (Java 14, standard en Java 16)
Les records simplifient la création de classes immuables conteneurs de données.
Java 8 (sans records)
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode() { ... }
@Override
public String toString() { ... }
}
Java 20
public record Person(String name, int age) {}
Avantages :
- Code réduit de ~30 lignes à 1 ligne
- Immutabilité garantie
- Equals/hashCode/toString générés automatiquement
- Support des records dans les switch (pattern matching)
2. Pattern Matching for switch (Java 21, preview en Java 20)
Les expressions switch sont maintenant plus puissantes avec le pattern matching.
Java 8
Object obj = ...;
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.toLowerCase());
} else if (obj instanceof Integer) {
System.out.println(obj * 2);
}
Java 20 (preview) / 21 (standard)
Object obj = ...;
switch (obj) {
case String s -> System.out.println(s.toLowerCase());
case Integer i -> System.out.println(i * 2);
case null -> System.out.println("Null value");
default -> System.out.println("Unknown");
}
Records avec pattern matching
record Point(int x, int y) {}
void process(Object o) {
switch (o) {
case Point(int x, int y) -> System.out.println("Point: " + x + "," + y);
case null -> System.out.println("Nothing");
default -> System.out.println("Other");
}
}
3. Text Blocks (Java 15, standard en Java 16)
Les text blocks simplifient l'écriture de chaînes multilignes.
Java 8
String json = "{\n" +
" \"name\": \"John\",\n" +
" \"age\": 30\n" +
"}";
Java 20
String json = """
{
"name": "John",
"age": 30
}
""";
Avantages :
- Pas besoin d'échapper les quotes
- Meilleure lisibilité
- Indentation naturelle
4. Optional Améliorations (Java 9+)
Java 8 a introduit Optional, mais Java 9+ l'a enrichi.
Java 8
Optional<String> optional = Optional.ofNullable(getValue());
if (optional.isPresent()) {
System.out.println(optional.get().toUpperCase());
}
Java 20 (avec améliorations successives)
Optional<String> optional = Optional.ofNullable(getValue());
// Optional.or() - Java 9
Optional<String> result = optional.or(() -> Optional.of("default"));
// Optional.stream() - Java 9
optional.stream().forEach(System.out::println);
// Optional.isEmpty() - Java 11
if (optional.isEmpty()) {
System.out.println("No value");
}
5. Virtual Threads (Project Loom, Java 21, preview en Java 20)
Les virtual threads révolutionnent la concurrence avec des threads légers.
Java 8 (platform threads)
// Chaque thread = 1 OS thread (coûteux)
ExecutorService executor = Executors.newFixedThreadPool(100);
executor.submit(() -> {
// Traitement
});
Java 20/21 (virtual threads)
// Virtual threads - légers, millions peuvent coexister
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
executor.submit(() -> {
// Traitement
});
Cas d'usage : Serveurs haute concurrence, microservices.
6. Switch Expressions (Java 14, standard en Java 12)
Les switch deviennent des expressions avec yield.
Java 8
int days;
switch (month) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
days = 31;
break;
case 4: case 6: case 9: case 11:
days = 30;
break;
case 2:
days = 28;
break;
default:
days = 0;
}
Java 20
int days = switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> 31;
case 4, 6, 9, 11 -> 30;
case 2 -> 28;
default -> 0;
};
Avec yield pour des blocs plus complexes :
int result = switch (value) {
case 1 -> {
yield 10;
}
case 2 -> {
int x = value * 2;
yield x + 5;
}
default -> 0;
};
7. Records Patterns (Java 21)
Les records s'intègrent parfaitement avec les patterns.
record Point(int x, int y) {}
record Rectangle(Point upperLeft, Point lowerRight) {}
void process(Rectangle rect) {
// Déconstruction directe
if (rect instanceof Rectangle(Point(int x1, int y1), Point(int x2, int y2))) {
System.out.println("Rectangle from (" + x1 + "," + y1 + ") to (" + x2 + "," + y2 + ")");
}
}
8. Strongly Encapsulate JDK Internals (Java 16+)
Par défaut, l'accès aux API internes (sun.misc.Unsafe, etc.) est restreint.
Message d'erreur typique
ERROR: Access denied for sun.misc.Unsafe
Solution
Soit on utilise l'API officielle, soit on ajoute des options :
--add-opens java.base/java.util=ALL-UNNAMED
Meilleure pratique : Éviter les internal APIs, utiliser les alternatives officielles.
9. Type Inference for Local Variables (Java 10)
Le mot-clé var pour les variables locales.
Java 8
List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();
Java 20
var list = new ArrayList<String>();
var map = new HashMap<String, Integer>();
Note : var n'est pas une keyword, juste un type réservé. Ne s'applique qu'aux variables locales.
10. Multi-File Source-Code Execution (Java 11+)
Lancer un fichier Java unique sans compilation préalable.
Java 8
javac Main.java
java Main
Java 20
java Main.java
Fonctionne même avec plusieurs fichiers dans le même répertoire.
11. Concise Method Bodies (Java 21, preview)
Syntaxe simplifiée pour les méthodes sans paramètres.
// Preview en Java 21
class DateUtils {
int year() { 365; } // Return implicite
String season() {
switch (month) {
case 12, 1, 2 -> "Winter";
case 3, 4, 5 -> "Spring";
// ...
}
}
}
Migration : Checklist Pratique
Étape 1 : Mise à jour du JDK
# Vérifier la version
java -version
# Installer Java 20/21
# Ubuntu/Debian : apt install openjdk-21-jdk
# macOS : brew install openjdk
Étape 2 : Mise à jour du build
Maven (pom.xml)
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
Gradle (build.gradle)
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
Étape 3 : Réfactoring progressif
- Remplacer les POJOs par des records
- Utiliser le pattern matching dans les switch
- Adopter les text blocks pour les chaînes multilignes
- Remplacer Optional.isEmpty() par isEmpty() (Java 11+)
- Utiliser
varpour les variables locales
Étape 4 : Gestion des breaking changes
- Joueur avec les
--add-openssi nécessaire - Vérifier les dépendances tierces
- Tests automatisés pour valider la migration
Conclusion
Java 20/21 n'est pas une révolution comme Java 8, mais une évolution continue qui rend le langage plus expressif et plus performant.
Points à retenir :
- Records — Simplifient les classes de données
- Pattern matching — Switch plus puissant avec déconstruction
- Virtual threads — Concurrence à grande échelle
- Text blocks — Chaînes multilignes naturelles
- var — Inférence de type pour les locales
Pour une migration réussie, procédez progressivement, testez chaque nouvelle fonctionnalité et profitez des outils modernes de Java.
Annexe : Chronologie des fonctionnalités
| Version | Date | Fonctionnalités majeures |
|---|---|---|
| 8 | 2014 | Lambda, Stream, Optional, Date API |
| 9 | 2017 | Modules, JShell, Optional.or/stream |
| 10 | 2018 | var, G1 GC par défaut |
| 11 | 2018 | LTS, var, isEmpty() |
| 14 | 2020 | Records (preview), Switch expressions |
| 15 | 2020 | Text blocks, Sealed classes |
| 16 | 2021 | Records (standard), Pattern matching |
| 17 | 2021 | LTS, Sealed classes, Pattern matching |
| 19 | 2022 | Text blocks (standard), Virtual threads |
| 20 | 2023 | Virtual threads (preview), Records patterns |
| 21 | 2023 | Virtual threads (standard), Pattern matching (standard) |