JEP 427, Pattern Matching for switch (Third Preview)
Contexte
Rappel : Principe
Le principe est comme le filtrage par motif pour instanceof
mais en l’appliquant au switch
.
Pour plus d’informations sur le filtrage par motif pour instanceof
, je vous conseille cette article JEP 375 - Pattern Matching for instanceof (Second Preview)
Initialement, nous avons le code suivant :
static String formatter(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
L’objectif est de pouvoir utiliser un filtrage par motif au niveau du switch
(et même une expression switch
).
static String formatterPatternSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
Pour reprendre l’ensemble des fonctionnalités du filtrage par motif, je vous conseille l’article initiale sur cette fonctionnalité JEP 406 - Pattern Matching for switch (Preview)
Nouveautés
Traitement du null
Jusqu’à présent, la déclaration ou l’expression switch
avec une valeur null
lève une exception NullPointerException
. C’est pourquoi, généralement, le switch
est protégé par l’instruction if
.
static void testFooBar(String s) {
if (s == null) {
System.out.println("Oops!");
return;
}
switch (s) {
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
Maintenant, nous pourrons écrire un label null
pour traiter ce cas. Nous pouvons écrire :
static void testFooBar(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
Le label peut être mélangé avec un autre. Par exemple, nous pouvons écrire aussi
static void testStringOrNull(Object o) {
switch (o) {
case null, String s -> System.out.println("String: " + s);
default -> System.out.println("Something else");
}
}
Pour de raisons de compatibilité, si la valeur du sélecteur est nulle
, le switch
lève une exception NullPointerException
. C’est à dire que le code suivant :
static void test(Object o) {
switch (o) {
case String s -> System.out.println("String: " + s);
case Integer i -> System.out.println("Integer");
default -> System.out.println("default");
}
}
est équivalent à celui-ci
static void test(Object o) {
switch (o) {
case null -> throw new NullPointerException();
case String s -> System.out.println("String: "+s);
case Integer i -> System.out.println("Integer");
default -> System.out.println("default");
}
}
Là encore, c’est le compilateur qui fait le travail.
Raffinement des cas
Au delà du motif avec le type correspondant, nous pourrions avoir des conditions supplémentaires qui permet de raffiner le cas.
Prenons un exemple avec les classes suivantes : Forme
, Rectangle
et Triangle
:
class Forme {}
class Rectangle extends Forme {}
class Triangle extends Forme { int calculerAire() { ... } }
Nous pouvons traiter par type, entre Rectangle
et Triangle
. Cependant, nous aimerions définir des conditions supplémentaires. Par exemple, nous voulons traiter les triangles dont l’aire est supérieur à 100.
Voici le code que nous devons écrire :
static void testTriangle(Forme f) {
switch (f) {
case null:
break;
case Triangle t:
if (t.calculerAire() > 100) {
System.out.println("Grand triangle");
break;
}
default:
System.out.println("Une forme, qui peut être un petit triangle");
}
}
----
Avec cette JEP, un nouveau mot-clé when
est introduit. Il permet de raffiner le cas. Dans notre exemple, nous avons t.calculateArea() > 100
static void testTriangle(Forme f) {
switch (f) {
case Triangle t
when t.calculerAire() > 100 ->
System.out.println("Grand triangle");
default ->
System.out.println("Une forme, qui peut être un petit triangle");
}
}
Là encore, il est possible de mixer les composants :
static void testTriangle(Forme f) {
switch (f) {
case Triangle t
when t.calculerAire() > 100 ->
System.out.println("Grand triangle");
case Triangle t ->
// Soit les triangles inférieur ou égale à 100
System.out.println("Petit triangle");
default ->
System.out.println("Forme autre que triangle");
}
}
Personnellement, j’adore cette possibilité. et vous ?
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