Istruzione Java Switch

1. Panoramica

In questo tutorial impareremo cos'è l' istruzione switch e come usarla.

L' istruzione switch ci consente di sostituire diversi costrutti if-else annidati e quindi migliorare la leggibilità del nostro codice.

Switch si è evoluto nel tempo: sono stati aggiunti nuovi tipi supportati, in particolare in Java 5 e 7. Inoltre, continua a evolversi: è probabile che le espressioni di switch verranno introdotte in Java 12.

Di seguito forniremo alcuni esempi di codice per dimostrare l'uso dell'istruzione switch , il ruolo dell'istruzione break , i requisiti per l' argomento switch / valori case e il confronto di String s in un'istruzione switch .

Passiamo all'esempio.

2. Esempio di utilizzo

Diciamo che abbiamo le seguenti istruzioni if-else annidate :

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; }

Il codice sopra non ha un bell'aspetto e sarebbe difficile da mantenere e ragionare. Per migliorare la leggibilità, potremmo utilizzare un'istruzione switch qui:

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; }

Come mostrato sopra, confrontiamo l' argomento switch animal con i diversi valori case . Se nessuno dei valori del caso è uguale all'argomento, viene eseguito il blocco sotto l' etichetta predefinita .

In poche parole, l' istruzione break viene utilizzata per uscire da un'istruzione switch .

3. L' istruzione break

Sebbene la maggior parte delle istruzioni switch nella vita reale implichino che solo uno dei blocchi case dovrebbe essere eseguito, l' istruzione break è necessaria per uscire da uno switch dopo il completamento del blocco.

Se dimentichiamo di scrivere un'interruzione , i blocchi sottostanti verranno eseguiti.

Per dimostrarlo omettiamo le istruzioni break e aggiungiamo l'output alla console per ogni blocco:

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

Eseguiamo questo codice dimenticareBreakInSwitch ( "DOG") e controlliamo l'output per dimostrare che tutti i blocchi vengono eseguiti:

domestic animal unknown animal

Quindi dovremmo stare attenti e aggiungere istruzioni break alla fine di ogni blocco a meno che non sia necessario passare al codice sotto l'etichetta successiva.

L'unico blocco in cui un'interruzione non è necessaria è l'ultimo, ma l'aggiunta di un'interruzione all'ultimo blocco rende il codice meno soggetto a errori.

Possiamo anche trarre vantaggio da questo comportamento per omettere break quando vogliamo che lo stesso codice venga eseguito per diverse istruzioni case. Riscriviamo l'esempio nella sezione precedente raggruppando i primi 2 casi:

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 Argomento e Valori case

Ora discutiamo i tipi consentiti di argomenti switch e valori case , i requisiti per essi e il modo in cui l' istruzione switch funziona con le stringhe.

4.1. Tipi di dati

Non possiamo confrontare tutti i tipi di oggetti e primitive nell'istruzione switch . Uno switch funziona solo con quattro primitive e i loro wrapper, così come con il tipo enum e la classe String :

  • byte e byte
  • breve e breve
  • int e Integer
  • char e carattere
  • enum
  • Corda

Il tipo di stringa è disponibile nell'istruzione switch che inizia con Java 7.

Il tipo enum è stato introdotto in Java 5 e da allora è disponibile nell'istruzione switch .

Le classi wrapper sono disponibili anche da Java 5.

Ovviamente, l' argomento switch ei valori case dovrebbero essere dello stesso tipo.

4.2. Non ci sono nulli Valori

Non possiamo passare il valore null come argomento a un'istruzione switch . Se lo facciamo, il programma lancerà NullPointerException, utilizzando il nostro primo esempio di switch :

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

Ovviamente, non possiamo anche passare null come valore all'etichetta case di un'istruzione switch . Se lo facciamo, il codice non verrà compilato.

4.3. Valori case come costanti in fase di compilazione

Se proviamo a sostituire il valore del caso DOG con la variabile dog, il codice non verrà compilato fino a quando non contrassegneremo la variabile dog come 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. Confronto tra stringhe

Se un'istruzione switch utilizza l'operatore di uguaglianza per confrontare le stringhe, non è possibile confrontare correttamente un argomento String creato con l' operatore new con un valore case String .

Fortunatamente, l' operatore di commutazione utilizza il metodo equals () sotto il cofano .

Dimostriamo questo:

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

5. switch 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

In questo tutorial, abbiamo appreso le sottigliezze dell'utilizzo dell'istruzione switch in Java. Possiamo decidere se utilizzare switch in base alla leggibilità e al tipo di valori confrontati.

L'istruzione switch è un buon candidato per i casi in cui abbiamo un numero limitato di opzioni in un insieme predefinito (ad esempio: giorni della settimana). In caso contrario, dovremmo modificare il codice ogni volta che viene aggiunto o rimosso un nuovo valore, il che potrebbe non essere fattibile. Per questi casi, dovremmo considerare altri approcci come il polimorfismo o altri modelli di progettazione come Command.

Come sempre il codice JDK 8 completo e il codice JDK 13 sono disponibili su GitHub.