Instruction Java Switch

1. Vue d'ensemble

Dans ce didacticiel, nous allons découvrir ce qu'est l' instruction switch et comment l'utiliser.

L' instruction switch nous permet de remplacer plusieurs constructions if-else imbriquées et d'améliorer ainsi la lisibilité de notre code.

Switch a évolué au fil du temps - de nouveaux types pris en charge ont été ajoutés, en particulier dans Java 5 et 7. De plus, il continue d'évoluer - des expressions de commutation seront probablement introduites dans Java 12.

Ci-dessous, nous donnerons quelques exemples de code pour illustrer l'utilisation de l' instruction switch , le rôle de l' instruction break , les exigences pour les valeurs d' argument / case switch et la comparaison de String s dans une instruction switch .

Passons à l'exemple.

2. Exemple d'utilisation

Disons que nous avons les instructions if-else imbriquées suivantes :

public String exampleOfIF(String animal) { String result; if (animal.equals("DOG") || animal.equals("CAT")) { result = "domestic animal"; } else if (animal.equals("TIGER")) { result = "wild animal"; } else { result = "unknown animal"; } return result; }

Le code ci-dessus n'a pas l'air bien et serait difficile à maintenir et à raisonner. Pour améliorer la lisibilité, nous pourrions utiliser une instruction switch ici:

public String exampleOfSwitch(String animal) { String result; switch (animal) { case "DOG": result = "domestic animal"; break; case "CAT": result = "domestic animal"; break; case "TIGER": result = "wild animal"; break; default: result = "unknown animal"; break; } return result; }

Comme indiqué ci-dessus, nous comparons l' argument de commutation animal avec les différentes valeurs de cas . Si aucune des valeurs de cas n'est égale à l'argument, alors le bloc sous l' étiquette par défaut est exécuté.

En termes simples, l' instruction break est utilisée pour quitter une instruction switch .

3. La déclaration break

Bien que la plupart des instructions switch dans la vie réelle impliquent qu'un seul des blocs case doit être exécuté, l' instruction break est nécessaire pour quitter un switch une fois le bloc terminé.

Si nous oublions d'écrire une pause , les blocs en dessous seront exécutés.

Pour illustrer cela, omettons les instructions break et ajoutons la sortie à la console pour chaque bloc:

public String forgetBreakInSwitch(String animal) { switch (animal) { case "DOG": System.out.println("domestic animal"); default: System.out.println("unknown animal"); } }

Exécutons ce code forgetBreakInSwitch ( «DOG»), et vérifions la sortie pour prouver que tous les blocs sont exécutés:

domestic animal unknown animal

Nous devons donc être prudents et ajouter des instructions break à la fin de chaque bloc à moins qu'il ne soit nécessaire de passer au code sous l'étiquette suivante.

Le seul bloc où une rupture n'est pas nécessaire est le dernier, mais l'ajout d'une rupture au dernier bloc rend le code moins sujet aux erreurs.

Nous pouvons également profiter de ce comportement pour omettre break lorsque nous voulons que le même code soit exécuté pour plusieurs instructions case. Réécrivons l'exemple de la section précédente en regroupant les 2 premiers cas:

public String exampleOfSwitch(String animal) { String result; switch (animal) { case "DOG": case "CAT": result = "domestic animal"; break; case "TIGER": result = "wild animal"; break; default: result = "unknown animal"; break; } return result; }

4. switch Argument et case Values

Discutons maintenant des types autorisés d' argument switch et de valeurs de cas , de leurs exigences et du fonctionnement de l' instruction switch avec Strings.

4.1. Types de données

Nous ne pouvons pas comparer tous les types d'objets et de primitives dans l' instruction switch . Un commutateur fonctionne uniquement avec quatre primitives et leurs wrappers, ainsi qu'avec le type enum et la classe String :

  • octet et octet
  • court et court
  • int et Integer
  • char et caractère
  • énumération
  • Chaîne

Le type de chaîne est disponible dans l' instruction switch à partir de Java 7.

enum type a été introduit dans Java 5 et est disponible depuis lors dans l' instruction switch .

Les classes wrapper sont également disponibles depuis Java 5.

Bien entendu, les valeurs d' argument de commutation et de cas doivent être du même type.

4.2. Aucun null Valeurs

Nous ne pouvons pas passer la valeur null comme argument à une instruction switch . Si nous le faisons, le programme lancera NullPointerException, en utilisant notre premier exemple de commutateur :

@Test(expected=NullPointerException.class) public void whenSwitchAgumentIsNull_thenNullPointerException() { String animal = null; Assert.assertEquals("domestic animal", s.exampleOfSwitch(animal)); }

Bien sûr, nous ne pouvons pas également passer null comme valeur à l' étiquette de cas d'une instruction switch . Si nous le faisons, le code ne se compilera pas.

4.3. Valeurs de cas en tant que constantes au moment de la compilation

Si nous essayons de remplacer la valeur de cas DOG par la variable dog, le code ne sera pas compilé jusqu'à ce que nous marquions la variable dog comme finale :

final String dog="DOG"; String cat="CAT"; switch (animal) { case dog: //compiles result = "domestic animal"; case cat: //does not compile result = "feline" }

4.4. Comparaison des chaînes

Si une instruction switch utilisait l'opérateur d'égalité pour comparer des chaînes, nous ne pouvions pas comparer correctement un argument String créé avec le nouvel opérateur à une valeur de cas String .

Heureusement, l' opérateur de commutation utilise la méthode equals () sous le capot .

Démontrons ceci:

@Test public void whenCompareStrings_thenByEqual() { String animal = new String("DOG"); assertEquals("domestic animal", s.exampleOfSwitch(animal)); }

5. changer d' expressions

JDK 13 is now available and brings an improved version of a new feature first introduced in JDK 12: the switch expression.

In order to enable it, we need to pass –enable-preview to the compiler.

5.1. The New switch Expression

Let's see what the new switch expression looks like when switching over months:

var result = switch(month) { case JANUARY, JUNE, JULY -> 3; case FEBRUARY, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER -> 1; case MARCH, MAY, APRIL, AUGUST -> 2; default -> 0; }; 

Sending in a value like Month.JUNE would set result to 3.

Notice that the new syntax uses the ->operator instead of the colon we're used to with switch statements. Also, there's no break keyword: The switch expression doesn't fall through cases.

Another addition is the fact that we can now have comma-delimited criteria.

5.2. The yield Keyword

Going a bit further, there's a possibility to obtain fine-grained control over what's happening on the right side of the expression by using code blocks. In such a case, we need to use the keyword yield:

var result = switch (month) { case JANUARY, JUNE, JULY -> 3; case FEBRUARY, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER -> 1; case MARCH, MAY, APRIL, AUGUST -> { int monthLength = month.toString().length(); yield monthLength * 4; } default -> 0; };

While our example is a bit arbitrary, the point here is that we've got access to more of the Java language here.

5.3. Returning Inside switch Expressions

As a consequence of the distinction between switch statements and switch expressions, it is possible to return from inside a switch statement, but we're not allowed to do so from within a switch expression.

The following example is perfectly valid and will compile:

switch (month) { case JANUARY, JUNE, JULY -> { return 3; } default -> { return 0; } }

However, the following code will not compile, as we are trying to return outside of an enclosing switch expression:

var result = switch (month) { case JANUARY, JUNE, JULY -> { return 3; } default -> { return 0; } };

5.4. Exhaustiveness

When using switch statements, it doesn't really matter if all cases are covered.

The following code, for example, is perfectly valid and will compile:

switch (month) { case JANUARY, JUNE, JULY -> 3; case FEBRUARY, SEPTEMBER -> 1; }

For switch expressions though, the compiler insists that all possible cases are covered. The following code snippet, for example, would not compile, as there's no default case and not all possible cases are covered:

var result = switch (month) { case JANUARY, JUNE, JULY -> 3; case FEBRUARY, SEPTEMBER -> 1; }

The switch expression, however, will be valid when all possible cases are covered, like in the following example:

var result = switch (month) { case JANUARY, JUNE, JULY -> 3; case FEBRUARY, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER -> 1; case MARCH, MAY, APRIL, AUGUST -> 2; }

Please note that the above code snippet does not have a default case. As long as all cases are covered, the switch expression will be valid.

6. Conclusion

Dans ce didacticiel, nous avons appris les subtilités de l'utilisation de l' instruction switch en Java. Nous pouvons décider d'utiliser le commutateur en fonction de la lisibilité et du type des valeurs comparées.

L'instruction switch est un bon candidat pour les cas où nous avons un nombre limité d'options dans un ensemble prédéfini (par exemple: jours de la semaine). Sinon, nous devrons modifier le code à chaque fois qu'une nouvelle valeur est ajoutée ou supprimée, ce qui peut ne pas être possible. Pour ces cas, nous devrions envisager d'autres approches telles que le polymorphisme ou d'autres modèles de conception comme Command.

Comme toujours, le code JDK 8 complet et le code JDK 13 sont disponibles sur GitHub.