La sortie du Java Development Kit (JDK) 23, en septembre 2024, marque une étape importante dans l'histoire du langage de programmation Java, un outil robuste, polyvalent et essentiel dans l'environnement du développement logiciel.
Depuis 1995, lorsque Java a été présenté pour la première fois par Sun Microsystems avec le slogan "Write Once, Run Anywhere", il permet de faire tourner du code sur n'importe quel appareil. Au fil des années, Java a évolué à travers différentes versions, introduisant de nouvelles fonctionnalités et des améliorations tout en maintenant la compatibilité avec les versions antérieures.
Cette tradition se poursuit avec cette nouvelle version, qui vise à améliorer la productivité des développeurs et les performances des applications, tout en s'assurant que Java reste pertinent et puissant.
Cette version comprend un total de 12 propositions d'amélioration de Java (Java Enhancement Proposals, ou JEPs), à savoir :
Regardons de plus près certaines des mises à jour, selon nous pertinentes.
Cette nouvelle fonctionnalité a pour objectifs de :
Exemple :
//improve the switch expression:
switch (x.getStatus()) {
case 0 -> "ok";
case 1 -> "warning";
case 2 -> "error";
default -> "unknown status: " + x.getStatus();
}
//exposing the matched value:
switch (x.getStatus()) {
case 0 -> "okay";
case 1 -> "warning";
case 2 -> "error";
case int i -> "unknown status: " + i;
}
//allowing guards to inspect the corresponding value:
switch (x.getYearlyFlights()) {
case 0 -> ...;
case 1 -> ...;
case 2 -> issueDiscount();
case int i when i >= 100 -> issueGoldCard();
case int i -> ... appropriate action when i > 2 && i < 100 ...
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
Dans le langage de programmation Java, les constructeurs permettent de placer des instructions avant un appel explicite à un constructeur, tel que super(..)ou this(..). Bien que ces instructions ne puissent pas référencer l'instance en cours de construction, elles peuvent initialiser ses champs.
Initialiser les champs avant d'invoquer un autre constructeur améliore la fiabilité des classes, en particulier lorsque des méthodes sont surchargées. Cette fonctionnalité est actuellement en phase d'aperçu.
Exemple :
//Flexible Constructor Bodies
class Parent {
int x;
public Parent(int x) {
this.x = x;
}
}
class Child extends Parent {
int y;
public Child(int x, int y) {
// Statements before calling the parent constructor
int temp = x * 2; // Cannot reference instance fields
super(temp); // Explicit constructor invocation
this.y = y; // Instance fields can be initialized after the invocation
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child(5, 10);
System.out.println("x: " + child.x + ", y: " + child.y); // Outputs: x: 10, y: 10
}
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
La fonctionnalité de concurrence structurée simplifie la programmation multithread en traitant plusieurs tâches exécutées dans différents threads comme une seule unité de travail, ce qui facilite la gestion des erreurs et l'annulation.
Exemple :
// Structured Concurrency
public class StructuredConcurrencyExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> future1 = scope.fork(() -> fetchDataFromService1());
Future<String> future2 = scope.fork(() -> fetchDataFromService2());
scope.join(); // Join both forks
scope.throwIfFailed(); // Propagate exceptions
String result1 = future1.resultNow();
String result2 = future2.resultNow();
System.out.println(result1 + " " + result2);
}
}
private static String fetchDataFromService1() {
// Simulate fetching data
return "Data1";
}
private static String fetchDataFromService2() {
// Simulate fetching data
return "Data2";
}
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
Les valeurs à portée permettent aux méthodes de partager des données immuables avec leurs sous-fonctions au sein d'un thread et avec les threads enfants. Elles sont plus simples à comprendre par rapport aux variables locales de thread et offrent des coûts moindres en termes d'espace et de temps.
Lorsqu'elles sont utilisées avec les threads virtuels et la concurrence structurée, les valeurs à portée sont particulièrement efficaces. Cette fonctionnalité est actuellement une API en aperçu.
Exemple :
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import jdk.incubator.concurrent.ScopedValue;
public class Main {
public static void main(String[] args) {
ScopedValue<String> scopedValue = ScopedValue.create("Hello, World!");
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
System.out.println("Scoped Value: " + scopedValue.get());
});
executor.shutdown();
}
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
Cette fonctionnalité vise à améliorer l'API des flux Java en introduisant deux nouvelles opérations terminales : Stream.gather(toList(), toSet()) et Stream.gather(toMap(), toSet()). Ces opérations permettent de collecter les éléments d'un flux dans plusieurs collections simultanément, ce qui simplifie le code et améliore la lisibilité lorsque le flux doit être collecté dans plusieurs conteneurs.
La fonctionnalité, initialement proposée dans Java 22, a été affinée en fonction des retours et est maintenant présentée pour un deuxième aperçu afin de s'assurer que sa fonctionnalité et ses performances répondent aux besoins de la communauté avant sa finalisation.
Exemple :
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamGatherersExample {
public static void main(String[] args) {
// Example stream
Stream<String> stream = Stream.of("apple", "banana", "cherry", "apple", "date", "banana");
// Using Stream.gather to collect elements into a List and a Set simultaneously
var result = stream.collect(Collectors.gather(
Collectors.toList(),
Collectors.toSet()
));
// Extracting the results
List<String> list = result.getFirst();
Set<String> set = result.getSecond();
// Printing the results
System.out.println("List: " + list);
System.out.println("Set: " + set);
}
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
Voici mes conseils pour les développeurs Java utilisant la nouvelle version Java 23 :
Adoptez des techniques de codage efficaces :
Directives pour la gestion des erreurs :
Stratégies d'optimisation des performances :
Java 23 introduit un ensemble de fonctionnalités et d'améliorations avancées conçues pour améliorer l'efficacité et les performances du développement logiciel, tout en renforçant la compatibilité et l'interopérabilité de Java avec d'autres langages et plateformes. Cette version inclut des améliorations de la Java Virtual Machine (JVM), de nouvelles fonctionnalités de langage, et des mises à jour des API et bibliothèques existantes, le tout visant à fournir aux développeurs davantage d'outils pour écrire un code performant et maintenable. Parmi les fonctionnalités notables, on trouve les améliorations de la correspondance de motifs pour les expressions switch, les améliorations de l'API des fonctions et de la mémoire étrangères, ainsi que de nouvelles options pour la collecte des déchets, qui contribuent collectivement à la robustesse et à l'adaptabilité des applications Java dans des environnements diversifiés.
En tant que développeur Java expérimenté, je trouve les nouvelles fonctionnalités de Java 23 à la fois passionnantes et essentielles pour le développement moderne. Les améliorations de la correspondance de motifs simplifient la logique conditionnelle complexe, rendant le code plus lisible et plus facile à maintenir. Les améliorations de l'API des fonctions et de la mémoire étrangères sont particulièrement importantes car elles ouvrent de nouvelles possibilités pour l'intégration de Java avec du code natif et d'autres langages, renforçant la polyvalence de Java dans les écosystèmes multilingues.
Dans l'ensemble, Java 23 poursuit la tradition d'évolution du langage et de la plateforme pour répondre aux besoins contemporains du développement, garantissant que Java reste un choix de premier plan pour les développeurs du monde entier.
La sortie du Java Development Kit (JDK) 23, en septembre 2024, marque une étape importante dans l'histoire du langage de programmation Java, un outil robuste, polyvalent et essentiel dans l'environnement du développement logiciel.
Depuis 1995, lorsque Java a été présenté pour la première fois par Sun Microsystems avec le slogan "Write Once, Run Anywhere", il permet de faire tourner du code sur n'importe quel appareil. Au fil des années, Java a évolué à travers différentes versions, introduisant de nouvelles fonctionnalités et des améliorations tout en maintenant la compatibilité avec les versions antérieures.
Cette tradition se poursuit avec cette nouvelle version, qui vise à améliorer la productivité des développeurs et les performances des applications, tout en s'assurant que Java reste pertinent et puissant.
Cette version comprend un total de 12 propositions d'amélioration de Java (Java Enhancement Proposals, ou JEPs), à savoir :
Regardons de plus près certaines des mises à jour, selon nous pertinentes.
Cette nouvelle fonctionnalité a pour objectifs de :
Exemple :
//improve the switch expression:
switch (x.getStatus()) {
case 0 -> "ok";
case 1 -> "warning";
case 2 -> "error";
default -> "unknown status: " + x.getStatus();
}
//exposing the matched value:
switch (x.getStatus()) {
case 0 -> "okay";
case 1 -> "warning";
case 2 -> "error";
case int i -> "unknown status: " + i;
}
//allowing guards to inspect the corresponding value:
switch (x.getYearlyFlights()) {
case 0 -> ...;
case 1 -> ...;
case 2 -> issueDiscount();
case int i when i >= 100 -> issueGoldCard();
case int i -> ... appropriate action when i > 2 && i < 100 ...
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
Dans le langage de programmation Java, les constructeurs permettent de placer des instructions avant un appel explicite à un constructeur, tel que super(..)ou this(..). Bien que ces instructions ne puissent pas référencer l'instance en cours de construction, elles peuvent initialiser ses champs.
Initialiser les champs avant d'invoquer un autre constructeur améliore la fiabilité des classes, en particulier lorsque des méthodes sont surchargées. Cette fonctionnalité est actuellement en phase d'aperçu.
Exemple :
//Flexible Constructor Bodies
class Parent {
int x;
public Parent(int x) {
this.x = x;
}
}
class Child extends Parent {
int y;
public Child(int x, int y) {
// Statements before calling the parent constructor
int temp = x * 2; // Cannot reference instance fields
super(temp); // Explicit constructor invocation
this.y = y; // Instance fields can be initialized after the invocation
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child(5, 10);
System.out.println("x: " + child.x + ", y: " + child.y); // Outputs: x: 10, y: 10
}
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
La fonctionnalité de concurrence structurée simplifie la programmation multithread en traitant plusieurs tâches exécutées dans différents threads comme une seule unité de travail, ce qui facilite la gestion des erreurs et l'annulation.
Exemple :
// Structured Concurrency
public class StructuredConcurrencyExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> future1 = scope.fork(() -> fetchDataFromService1());
Future<String> future2 = scope.fork(() -> fetchDataFromService2());
scope.join(); // Join both forks
scope.throwIfFailed(); // Propagate exceptions
String result1 = future1.resultNow();
String result2 = future2.resultNow();
System.out.println(result1 + " " + result2);
}
}
private static String fetchDataFromService1() {
// Simulate fetching data
return "Data1";
}
private static String fetchDataFromService2() {
// Simulate fetching data
return "Data2";
}
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
Les valeurs à portée permettent aux méthodes de partager des données immuables avec leurs sous-fonctions au sein d'un thread et avec les threads enfants. Elles sont plus simples à comprendre par rapport aux variables locales de thread et offrent des coûts moindres en termes d'espace et de temps.
Lorsqu'elles sont utilisées avec les threads virtuels et la concurrence structurée, les valeurs à portée sont particulièrement efficaces. Cette fonctionnalité est actuellement une API en aperçu.
Exemple :
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import jdk.incubator.concurrent.ScopedValue;
public class Main {
public static void main(String[] args) {
ScopedValue<String> scopedValue = ScopedValue.create("Hello, World!");
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
System.out.println("Scoped Value: " + scopedValue.get());
});
executor.shutdown();
}
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
Cette fonctionnalité vise à améliorer l'API des flux Java en introduisant deux nouvelles opérations terminales : Stream.gather(toList(), toSet()) et Stream.gather(toMap(), toSet()). Ces opérations permettent de collecter les éléments d'un flux dans plusieurs collections simultanément, ce qui simplifie le code et améliore la lisibilité lorsque le flux doit être collecté dans plusieurs conteneurs.
La fonctionnalité, initialement proposée dans Java 22, a été affinée en fonction des retours et est maintenant présentée pour un deuxième aperçu afin de s'assurer que sa fonctionnalité et ses performances répondent aux besoins de la communauté avant sa finalisation.
Exemple :
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamGatherersExample {
public static void main(String[] args) {
// Example stream
Stream<String> stream = Stream.of("apple", "banana", "cherry", "apple", "date", "banana");
// Using Stream.gather to collect elements into a List and a Set simultaneously
var result = stream.collect(Collectors.gather(
Collectors.toList(),
Collectors.toSet()
));
// Extracting the results
List<String> list = result.getFirst();
Set<String> set = result.getSecond();
// Printing the results
System.out.println("List: " + list);
System.out.println("Set: " + set);
}
}
Pour plus d'informations sur cette fonctionnalité, cliquez ici.
Voici mes conseils pour les développeurs Java utilisant la nouvelle version Java 23 :
Adoptez des techniques de codage efficaces :
Directives pour la gestion des erreurs :
Stratégies d'optimisation des performances :
Java 23 introduit un ensemble de fonctionnalités et d'améliorations avancées conçues pour améliorer l'efficacité et les performances du développement logiciel, tout en renforçant la compatibilité et l'interopérabilité de Java avec d'autres langages et plateformes. Cette version inclut des améliorations de la Java Virtual Machine (JVM), de nouvelles fonctionnalités de langage, et des mises à jour des API et bibliothèques existantes, le tout visant à fournir aux développeurs davantage d'outils pour écrire un code performant et maintenable. Parmi les fonctionnalités notables, on trouve les améliorations de la correspondance de motifs pour les expressions switch, les améliorations de l'API des fonctions et de la mémoire étrangères, ainsi que de nouvelles options pour la collecte des déchets, qui contribuent collectivement à la robustesse et à l'adaptabilité des applications Java dans des environnements diversifiés.
En tant que développeur Java expérimenté, je trouve les nouvelles fonctionnalités de Java 23 à la fois passionnantes et essentielles pour le développement moderne. Les améliorations de la correspondance de motifs simplifient la logique conditionnelle complexe, rendant le code plus lisible et plus facile à maintenir. Les améliorations de l'API des fonctions et de la mémoire étrangères sont particulièrement importantes car elles ouvrent de nouvelles possibilités pour l'intégration de Java avec du code natif et d'autres langages, renforçant la polyvalence de Java dans les écosystèmes multilingues.
Dans l'ensemble, Java 23 poursuit la tradition d'évolution du langage et de la plateforme pour répondre aux besoins contemporains du développement, garantissant que Java reste un choix de premier plan pour les développeurs du monde entier.