Nouveau Switch avec gardes en Java 21

L’évolution du pattern matching

Java 21 introduit une amélioration majeure avec les gardes when pour les expressions switch en Java 21. Cette fonctionnalité résout un problème fondamental : jusqu’à présent, le filtrage par motif était limité au type ou à la valeur exacte. Désormais, vous pouvez ajouter des conditions supplémentaires directement dans votre expression switch.

Imaginez when comme un filtre supplémentaire qui s’applique après la vérification de type. Il vous permet de dire : “Je ne veux pas juste n’importe quelle chaîne, mais une chaîne qui remplit cette condition spécifique.”

Syntaxe et fonctionnement du nouveau switch Java 21

Voici la structure de base pour utiliser les gardes when :

case Type variable when condition -> résultat;

Java suit un processus en trois étapes :

  1. Vérifier si l’objet est du type spécifié
  2. Si oui, lier la valeur à la variable nommée
  3. Évaluer la condition après when

Voici un exemple complet :

Object obj = getValue();
String result = switch(obj) {
    case String s when s.length() > 10 -> "Longue chaîne";
    case String s when s.startsWith("Java") -> "Chaîne Java";
    case String s -> "Chaîne ordinaire";
    case Integer i when i > 0 -> "Entier positif";
    case Integer i -> "Autre entier";
    default -> "Autre type";
};

Avant/Après : Visualiser l’amélioration

Pour comprendre l’impact réel, comparons l’approche avant Java 21 et avec Java 21 :

Avant Java 21

// Gestion d'articles dans une application e-commerce
switch(article) {
    case Livre l:
        if (l.getPrix() < 20.0) {
            return "Livre abordable";
        } else {
            return "Livre premium";
        }
    case Electronique e:
        if (e.getGarantie() > 12) {
            return "Protection étendue";
        } else {
            return "Garantie standard";
        }
    default:
        return "Article inconnu";
}

Avec Java 21

// La même logique, mais plus concise et claire
return switch(article) {
    case Livre l when l.getPrix() < 20.0 -> "Livre abordable";
    case Livre l -> "Livre premium";
    case Electronique e when e.getGarantie() > 12 -> "Protection étendue";
    case Electronique e -> "Garantie standard";
    default -> "Article inconnu";
};

Les avantages sont évidents :

  • Code plus compact (moins de lignes)
  • Structure visuelle plus cohérente
  • Élimination des imbrications if-else
  • Intention du code plus claire

Ordre d’évaluation et précautions

L’ordre des cas est critique. Java évalue vos cas séquentiellement, de haut en bas. Placez toujours les conditions les plus spécifiques en premier :

Correct ✅Incorrect ❌
case String s when s.startsWith("Java") -> "Chaîne Java";
case String s -> "Chaîne ordinaire";
case String s -> "Chaîne ordinaire";
case String s when s.startsWith("Java") -> "Chaîne Java";

Dans la version incorrecte, le deuxième cas ne sera jamais atteint car toutes les chaînes seront capturées par le premier cas.

Utilisation avec les records

Vous pouvez combiner des gardes when avec le pattern matching de records pour obtenir un code encore plus expressif :

record Point(int x, int y) {}

return switch(point) {
    case Point(int x, int y) when x > 0 && y > 0 -> "Premier quadrant";
    case Point(int x, int y) when x < 0 && y > 0 -> "Deuxième quadrant";
    case Point(int x, int y) when x < 0 && y < 0 -> "Troisième quadrant";
    case Point(int x, int y) when x > 0 && y < 0 -> "Quatrième quadrant";
    case Point(int x, int y) when x == 0 || y == 0 -> "Sur un axe";
    default -> "Point invalide";
};

Cas d’utilisation pratiques

Voici quelques situations où les gardes when brillent particulièrement :

  • Validation de données : Filtrer des objets selon des critères spécifiques
  • Traitement conditionnel : Appliquer différentes logiques selon les propriétés d’un objet
  • Analyse d’événements : Réagir différemment selon le type et les caractéristiques d’un événement
  • Parseurs et interpréteurs : Traiter des tokens ou des AST avec des patterns complexes
// Exemple : Traitement de messages dans une application de chat
return switch(message) {
    case TextMessage txt when txt.hasAttachments() -> processMessageWithAttachments(txt);
    case TextMessage txt when txt.getContent().length() > 100 -> summarizeMessage(txt);
    case TextMessage txt -> displayMessage(txt);
    case ImageMessage img when img.getSize() > 1_000_000 -> compressAndDisplay(img);
    case ImageMessage img -> displayImage(img);
    // ...autres types de messages
    default -> ignoreMessage();
};

Performance et compilation

Les gardes when sont traités au moment de la compilation. Le compilateur génère un code efficace qui combine les vérifications de type et les conditions supplémentaires. Il n’y a pas de pénalité significative en termes de performance par rapport à l’approche traditionnelle avec des blocs if-else imbriqués.

Compatibilité avec les versions antérieures

Cette fonctionnalité nécessite Java 21 ou supérieur. Si vous devez maintenir la compatibilité avec des versions antérieures, vous devrez continuer à utiliser l’approche traditionnelle avec des blocs if-else imbriqués.

Exercice pratique

Pour maîtriser cette fonctionnalité, essayez de refactoriser un code existant qui utilise des structures switch-if imbriquées. Identifiez les patterns qui peuvent être simplifiés avec les gardes when et réécrivez-les pour obtenir un code plus expressif.

Par exemple, transformez ce code :

switch(forme) {
    case Cercle c:
        if (c.getRayon() < 10) {
            return "Petit cercle";
        } else {
            return "Grand cercle";
        }
    case Rectangle r:
        if (r.getLargeur() > r.getHauteur()) {
            return "Rectangle horizontal";
        } else if (r.getLargeur() < r.getHauteur()) {
            return "Rectangle vertical";
        } else {
            return "Carré";
        }
    default:
        return "Forme inconnue";
}

En cette version plus concise et lisible :

return switch(forme) {
    case Cercle c when c.getRayon() < 10 -> "Petit cercle";
    case Cercle c -> "Grand cercle";
    case Rectangle r when r.getLargeur() > r.getHauteur() -> "Rectangle horizontal";
    case Rectangle r when r.getLargeur() < r.getHauteur() -> "Rectangle vertical";
    case Rectangle r -> "Carré";
    default -> "Forme inconnue";
};

Conclusion

Les gardes when dans les expressions switch en Java 21 représentent une avancée significative pour Java. Ils vous permettent d’écrire un code plus expressif, plus concis et plus maintenable, tout en éliminant les structures imbriquées complexes.

En adoptant cette fonctionnalité, vous rejoignez la tendance de Java vers un style de programmation plus déclaratif, où l’intention du code est immédiatement visible. C’est un pas de plus vers un Java plus moderne et plus expressif.