JEP 440, Records Pattern
Contexte
Le principe est l’utilisation des motifs introduits par filtrage par motif pour instanceof
, mais de l’appliquer pour les enregistrements.
Pour plus d’informations sur le filtrage par motif pour instanceof
, je vous conseille cette article JEP 394 - Pattern Matching for instanceof
Cette fonctionnalité a connu deux aperçu
Maintenant, c’est bien une fonctionnalité standard qui sera inclus dans le JDK 21.
Principe
L’objectif est d’écrire du code utilisant les deux fonctionnalités précédentes : Les enregistrements (Record) et les motifs (Patterns).
Prenons la définition de l’enregistrement Point
suivant :
record Point(int x, int y) {}
D’ores et déjà, nous pouvons écrire le code suivant avec le filtrage par motif pour instanceof
:
static void afficheSomme(Object o) {
if (o instanceof Point p) {
int a = p.x();
int b = p.y();
System.out.println(a + b);
}
}
Les classes classiques sont basées sur le principe de l’encapsulation. C’est à dire que nous connaissons le contrat de services via l’interface mais nous ne connaissons pas le détail de l’implémentation.
A l’inverse, les enregistrements (Record) mettent en avant leur structure interne. L’enregistrement Point
est composé d’une valeur x et d’une valeur y.
Par ce principe, nous allons pouvoir écrire l’instruction instanceof
comme ceci :
void afficheSomme(Object o) {
if (o instanceof Point(int a, int b)) {
System.out.println(a + b);
}
}
Pour aller plus loin
Nous pouvons manipuler des enregistrements plus complexe. Par exemple, prenons un enregistrement Rectangle
qui est composé de deux Point
:
record Rectangle(Point hautGauche, Point basDroit) {}
Par conséquent, nous pouvons écrire le code suivant :
static void afficheSommePointHautGauche(Rectangle r) {
if (r instanceof Rectangle(Point hg, Point bd)) {
System.out.println(hg.x() + hg.y());
}
}
Ce qui nous intéresse dans le code est le point haut à gauche, donc nous pouvons ignorer le second point.
static void afficheSommePointHautGauche(Rectangle r) {
if (r instanceof Rectangle(Point hg, var bd)) {
System.out.println(hg.x() + hg.y());
}
}
En revanche, nous savons qu’un Point
contient deux valeurs. Par conséquent, nous pouvons appliquer le même principe.
static void afficheSommePointHautGauche(Rectangle r) {
if (r instanceof Rectangle(Point(int a, int b) hg, var bd)) {
System.out.println(a + b);
}
}
Exhaustivité du switch
Prenons les définitions suivantes pour Forme
, Triangle
, Rectangle
et Paire
:
sealed interface Forme permits Triangle, Rectangle {}
final class Triangle implements Forme {}
final class Rectangle implements Forme {}
record Paire<T>(T x, T y) {}
Nous pouvons définir une variable comme celle-ci
Paire<Forme> p1 = ...;
L’interface Forme
est une interface scellée. Cela peut être soit une classe Triangle
, soit une classe de Rectangle
. Nous pouvons écrire l’instruction switch
suivante :
switch (p1) {
case Paire<Forme>(Triangle p, Forme s) -> ...
case Paire<Forme>(Rectangle p, Forme s) -> ...
}
Ci-dessus, l’ensemble des cas de l’instruction switch
est défini. Tous les combinaisons possibles sont traitées.
Maintenant, nous pouvons aussi écrire le code suivant :
switch (p1) {
case Paire<Forme>(Triangle p, Forme s) -> ...
case Paire<Forme>(Rectangle p, Triangle s) -> ...
case Paire<Forme>(Rectangle p, Rectangle s) -> ...
}
Nous avons simplement décomposé le deuxième cas du switch
(Rectangle
p, Forme
s) avec les différents cas possibles de Forme
: la classe Triangle
et la classe Rectangle
.
Maintenant, regardons le code suivant :
switch (p2) { // Erreur !
case Paire<Forme>(Triangle p, Rectangle s) -> ...
case Paire<Forme>(Rectangle p, Triangle s) -> ...
case Paire<Forme>(Forme p, Triangle s) -> ...
}
Ce dernier provoque une erreur de compilation car il manque le second cas avec le premier paramètre de type Forme
et le second paramètre de type Rectangle
.
Là encore, le compilateur nous aide pour traiter l’exhaustivité des cas pour l’écriture des switch
.
Cela est très utile pour la mise en place ou si on ajoute une nouvelle classe dérivée à l’interface scellée Forme
comme la classe Cercle
par exemple. Le compilateur signalera tous les endroits où des cas ne sont pas traités.
Moteur de recherche
"Eduquer, ce n'est pas remplir des vases mais c'est d'allumer des feux." - Michel Montaigne
Billets récents
- Eclipse plante systématiquement sous Debian (et autres distribution Linux)
- JEP 463, Implicitly Declared Classes and Instance Main Methods (Second Preview)
- Debian - Montée de version de Debian 11 (Bullseye) à Debian 12 (Bookworm)
- JEP 451, Prepare to Disallow the Dynamic Loading of Agents
- JEP 444, Virtual Threads