Switch et enhanced switch en java 17

Dans ce chapitre dédié à la Prendre décision en Java, nous explorons l’instruction switch et sa version moderne, l’expression switch. Ces outils vous permettent de contrôler le flux d’exécution de votre programme de manière claire et concise, en particulier lorsque plusieurs branches ou chemins doivent être traités pour une seule valeur. Grâce à cette approche, vous simplifierez la gestion de vos conditions et optimiserez votre code Java.

Utilisation de l’instruction switch

Que faire lorsqu’il existe de nombreuses branches possibles pour une seule valeur ? Par exemple, si l’on souhaite afficher un message différent selon le jour de la semaine, on pourrait utiliser sept instructions if/else. Cependant, cette méthode alourdit le code et le rend difficile à maintenir. Java offre alors une solution élégante avec l’instruction switch.

Une instruction switch évalue une valeur unique et redirige l’exécution vers la première branche correspondante, appelée case. Si aucune des valeurs ne correspond, une clause default facultative est exécutée. De plus, à partir de Java 14, il est possible de combiner plusieurs valeurs dans une même clause à l’aide de virgules.

Exemple classique avec l’instruction switch


public void imprimerJourDeLaSemaine(int jour) {
  switch(jour) {
    case 0:
      System.out.print("Dimanche");
      break;
    case 1:
      System.out.print("Lundi");
      break;
    case 2:
      System.out.print("Mardi");
      break;
    case 3:
      System.out.print("Mercredi");
      break;
    case 4:
      System.out.print("Jeudi");
      break;
    case 5:
      System.out.print("Vendredi");
      break;
    case 6:
      System.out.print("Samedi");
      break;
    default:
      System.out.print("Valeur invalide");
      break;
  }
}
  

Dans cet exemple, la méthode imprimerJourDeLaSemaine affiche le jour correspondant à la valeur de jour. Remarquez l’utilisation du mot-clé break qui permet de terminer l’instruction switch après avoir exécuté la branche correspondante.

Combinaison des valeurs de cas

Avec Java 14, il est désormais possible de combiner plusieurs valeurs dans une même clause case. Par exemple :


switch(animal) {
  case 1, 2:
    System.out.print("Lion");
    break;
  case 3:
    System.out.print("Tigre");
    break;
}
  

Avant Java 14, le même code aurait nécessité l’écriture répétée de case 1: case 2:.

Exercice pratique – Identifier les erreurs de syntaxe

Essayez de comprendre pourquoi les exemples de code suivants ne compilent pas :


int mois = 5;

switch mois { // Erreur : parenthèses manquantes autour de la variable
  case 1: System.out.print("Janvier");
}

switch(mois) // Erreur : accolades manquantes pour le bloc switch
  case 1: System.out.print("Janvier");

switch(mois) {
  case 1: 2: System.out.print("Janvier"); // Erreur : utilisation d'un deux-points au lieu d'une virgule pour combiner les cas
}
  

Dans ces exemples, des erreurs de syntaxe se produisent à cause de l’oubli des parenthèses, des accolades ou de la mauvaise séparation des valeurs de cas. Prenez le temps d’analyser ces erreurs pour bien comprendre la syntaxe requise par l’instruction switch.

Gestion des instructions break

Dans un switch traditionnel, l’instruction break termine l’exécution de la branche courante et renvoie le contrôle au bloc englobant. Sans break, toutes les branches suivantes seront exécutées, y compris la clause default.

Par exemple, considérez la méthode suivante qui illustre ce comportement :


public void imprimerSaison(int mois) {
  switch(mois) {
    case 1, 2, 3:
      System.out.print("Hiver");
      // Absence de break
    case 4, 5, 6:
      System.out.print("Printemps");
      // Absence de break
    default:
      System.out.print("Inconnu");
      // Absence de break
    case 7, 8, 9:
      System.out.print("Été");
      // Absence de break
    case 10, 11, 12:
      System.out.print("Automne");
      // Absence de break
  }
}
  

Appeler imprimerSaison(2) affichera : HiverPrintempsInconnuÉtéAutomne, car, sans les instructions break, toutes les branches sont exécutées successivement.

Données acceptées par l’instruction switch

L’instruction switch fonctionne avec plusieurs types de données. Voici un tableau récapitulatif des types supportés :

Type primitif / WrapperDescription
int / IntegerNombre entier
byte / ByteOctet
short / ShortEntier court
char / CharacterCaractère
StringChaîne de caractères
enumÉnumération
varSi le type se résout à l’un des types ci-dessus

Les expressions switch en Java

Pour réduire encore le code répétitif, Java 14 a introduit les expressions switch qui permettent d’affecter directement le résultat d’une instruction switch à une variable. Cela permet d’écrire un code plus compact et lisible.

Exemple d’expression switch pour imprimer le jour de la semaine


public void imprimerJourDeLaSemaine(int jour) {
  var resultat = switch(jour) {
    case 0 -> "Dimanche";
    case 1 -> "Lundi";
    case 2 -> "Mardi";
    case 3 -> "Mercredi";
    case 4 -> "Jeudi";
    case 5 -> "Vendredi";
    case 6 -> "Samedi";
    default -> "Valeur invalide";
  };
  System.out.print(resultat);
}
  

Dans cet exemple, l’expression switch renvoie une valeur qui est ensuite affectée à la variable resultat. Chaque branche est séparée par l’opérateur flèche (->) et un point-virgule est requis après chaque branche.

Utilisation de blocs dans une expression switch

Une expression switch peut utiliser à la fois des expressions et des blocs de code pour ses cas. Dans un bloc, la déclaration yield permet de retourner une valeur. Par exemple :


int poisson = 5;
int longueur = 12;
var nom = switch(poisson) {
  case 1 -> "Poisson Rouge";
  case 2 -> {
    yield "Truite";
  }
  case 3 -> {
    if(longueur > 10)
      yield "Poisson Blob";
    else
      yield "Vert";
  }
  default -> "Espadon";
};
  

Ici, la variable poisson est évaluée par l’expression switch et chaque branche retourne une chaîne de caractères grâce au mot-clé yield. Ainsi, le code reste concis tout en assurant une cohérence dans le type de données retourné.

Contraintes sur les valeurs de cas

Les valeurs utilisées dans une clause case doivent être des constantes de compilation de même type que la variable évaluée dans le switch. Cela signifie que seules des valeurs littérales, des constantes d’énumération ou des variables marquées final et initialisées lors de leur déclaration peuvent être utilisées.

Par exemple, dans le code suivant :


final int getBiscuits() {
  return 4;
}

public void nourrirAnimaux() {
  final int bananes = 1;
  int pommes = 2;
  int nombreDAnimaux = 3;
  final int biscuits = getBiscuits();
  switch(nombreDAnimaux) {
    case bananes:
    case pommes: // Erreur : 'pommes' n'est pas final
    case getBiscuits(): // Erreur : méthode évaluée à l'exécution
    case biscuits: // Erreur : même si final, la méthode n'est pas évaluable à la compilation
    case 3 * 5:
      System.out.print("Action");
  }
}
  

Seules les expressions évaluables à la compilation, comme bananes et 3 * 5, sont autorisées.

Retourner des types cohérents avec l’expression switch

Lorsque l’expression switch retourne une valeur, toutes les branches doivent fournir un type de donnée compatible. Par exemple, dans le code suivant, certaines branches ne compilent pas car elles retournent des types incompatibles avec la variable cible :


int mesure = 10;
int taille = switch(mesure) {
  case 5 -> 1;
  case 10 -> (short)2;
  default -> 5;
  case 20 -> "3"; // Erreur
  case 40 -> 4L; // Erreur
  case 50 -> null; // Erreur
};
  

Il est important que toutes les branches retournent des valeurs pouvant être affectées à la variable de destination.

Couverture de toutes les valeurs possibles

Une expression switch qui retourne une valeur doit gérer toutes les valeurs possibles de la variable évaluée. Deux solutions s’offrent à vous : ajouter une clause default ou, si la variable est de type énumération, fournir un cas pour chaque valeur.

Par exemple, considérons l’énumération suivante :


enum Saison {
  HIVER, PRINTEMPS, ÉTÉ, AUTOMNE
}

public String obtenirMétéo(Saison valeur) {
  return switch(valeur) {
    case HIVER -> "Froid";
    case PRINTEMPS -> "Pluvieux";
    case ÉTÉ -> "Chaud";
    case AUTOMNE -> "Doux";
  };
}
  

Ici, comme toutes les valeurs possibles de l’énumération Saison sont couvertes, la clause default est facultative. Toutefois, il est souvent recommandé d’en inclure une pour éviter des erreurs futures en cas d’extension de l’énumération.

En résumé, l’utilisation de l’instruction switch et des expressions switch en Java permet de simplifier la prise de décision en Java et d’écrire un code plus lisible et maintenable. Ces techniques sont essentielles pour gérer efficacement de multiples conditions dans vos applications Java, et vous permettront de développer des solutions robustes et évolutives.