Petit tour d’horizons sur les nouveautés java (pas si nouvelles que ça !)
Perso, je ne suis pas fan, ça me rappelle trop Javascript !
Avant Java 10 :
List<String> names = new ArrayList<>();
Depuis Java 10 :
var names = new ArrayList<String>();
Utilisable pour du JSON, XML et HTML.
Avant Java 13 :
String html = "<html>\n" + " <body>\n" + " <p>Hello World!</p>\n" + " </body>\n" + "</html>";
Depuis Java 13 :
String html = """ <html> <body> <p>Hello World!</p> </body> </html>""";
Avant Java 14 :
int numLetters; switch (day) { case MONDAY: case FRIDAY: case SUNDAY: numLetters = 6; break; case TUESDAY: numLetters = 7; break; case THURSDAY: case SATURDAY: numLetters = 8; break; case WEDNESDAY: numLetters = 9; break; }
Depuis Java 14 :
int numLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9; };
Ils permettent de vérifier si une valeur correspond à un certain modèle (par exemple, si une chaîne de caractères est un nombre entier, si un objet est de type List en le testant avec instanceof,…) et de décompacter cette valeur directement dans une variable.
import java.util.List; public class Example { public static void main(String[] args) { Object obj = List.of(1, 2, 3); if (obj instanceof List list) { // Décomposition de l'objet 'obj' dans la variable 'list' // si 'obj' est une instance de List System.out.println(list.size()); // Affiche 3 } if (obj instanceof List<Integer> list) { // Décomposition de l'objet 'obj' dans la variable 'list' // si 'obj' est une instance de List<Integer> System.out.println(list.stream().mapToInt(x -> x).sum()); // Affiche 6 } if (obj instanceof List<?> list) { // Décomposition de l'objet 'obj' dans la variable 'list' // si 'obj' est une instance de List<?> System.out.println(list.getClass()); // Affiche "class java.util.ImmutableCollections$ListN" } } }
Dans cet exemple, nous avons défini une variable obj qui contient une liste d’entiers.
Nous vérifions si obj correspond à différents modèles en utilisant des patterns matching. Si le modèle est vérifié, la valeur de obj est décomposée dans la variable correspondante (list dans notre exemple).
Nous pouvons alors utiliser cette variable comme n’importe quelle autre variable de type List !
Il permettent de définir des classes immuables qui ne contiennent que des champs privés, un constructeur, des accesseurs et un toString().
Les records sont utiles pour définir des types de données simples et lisibles avec peu de code comme ci-dessous :
La Classe point avant Java 14 :
class Point { private final int x; private final int y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } @Override public String toString() { return "Point{" + "x=" + x + ", y=" + y + '}'; } }
La classe Point depuis Java 14 :
record Point(int x, int y) { }
Fonctionnalité qui existe depuis la version 15 de Java.
Elles permettent de limiter les sous-classes pouvant être créées à partir d’une classe déclarée sealed comme ci-dessous :
sealed
sealed class Carte { // le sealed est toujours placé avant le mot-clé class }
Ensuite, il suffit d’ajouter les liste des classes autorisées après le mot-clé permits comme ci-dessous :
sealed class Carte permits CarteNumero, CarteSpeciale, CarteJoker { // Seules les classes après permits peuvent hériter de Carte } public final class CarteNumero extends Carte { // ici la classe est déclarée final pour empêcher d'en hériter // les classes final sont non modifiables et non étendables ! } public non-sealed class CarteSpeciale extends Carte { // cette classe possède le mot-clé non-sealed pour préciser qu'elle est normale et donc on peut en hériter ! } public final class CarteJoker extends Carte { // ici la classe est déclarée final pour empêcher d'en hériter comme avec CarteNumero }
Du coup, cette écriture ci-dessous est-elle possible ?
public class CarteBizarre extends Carte { // et bien NON, elle n'est pas dans la liste après permits ! }
C’est pratique si vous voulez restreindre les sous-classes autorisées pour des raisons de sécurité ou de conception. De plus, les classes scellées peuvent aussi être utilisées avec des expressions instanceof et switch pour faciliter la gestion des types.
Toute tentative d’étendre la classe scellée avec une classe qui n’est pas explicitement autorisée entraînera une erreur de compilation !
Elles sont particulièrement utiles pour définir des enums étendables…
Il permettent de définir des streams de données qui sont asynchrones, backpressure-aware et non bloquants.
Ils sont basés sur le modèle reactive stream et sont particulièrement utiles pour traiter des flux de données en temps réel.
import java.util.concurrent.Flow; public class Example { public static void main(String[] args) { Flow.Publisher<String> publisher = new MyPublisher(); Flow.Subscriber<String> subscriber = new MySubscriber(); publisher.subscribe(subscriber); } }
Les littéraux de chaîne en plusieurs parties permettent de définir des chaînes multilignes de manière plus concise et lisible. Ils suppriment la nécessité de utiliser des caractères d’échappement pour représenter des retours à la ligne ou des tabulations dans les chaînes de caractères.
String html = """ <html> <body> <p>Hello, world!</p> </body> </html> """;
L’opérateur de fusion de chaînes permet de concaténer des chaînes de manière plus concise et lisible. Il est particulièrement utile lorsque vous avez besoin de concaténer plusieurs chaînes de manière à ce qu’elles soient lisibles sur plusieurs lignes.
Il s’utilise en remplaçant le opérateur + habituellement utilisé pour concaténer des chaînes par le caractère |.
+
|
avant :
String greeting = "Hello, " + "world!"; // "Hello, world!"
après :
String greeting = "Hello, " | "world!"; // "Hello, world!"
L’opérateur de fusion de chaînes est particulièrement utile lorsque vous avez besoin de concaténer plusieurs chaînes de manière à ce qu’elles soient lisibles sur plusieurs lignes :
String html = "<html>" | "<body>" | " <p>Salut, l'univers !</p>" | "</body>" | "</html>";
Il permet également de concaténer des chaînes qui sont stockées dans des variables ou des expressions :
int x = 1; int y = 2; String message = "La somme de " | x | " et " | y | " est " | (x + y); // "La somme de 1 et 2 est 3"
Les annotations de type améliorées permettent d’ajouter des contraintes sur les types de données.
Dans l’exemple ci-dessous, la variable name ne peut pas être null et la liste numbers ne peut pas être vide et doit contenir des entiers positifs.
Ces annotations de type peuvent être utilisées pour améliorer la qualité du code et pour aider les outils de vérification de type à détecter des erreurs de manière plus précoce.
import java.util.List; class Example { @NonNull String name; @NonEmpty List<@Positive Integer> numbers; }