Istruzione switch in Java
- L'istruzione
switch
in Java consente di indirizzare l'esecuzione a parti diverse del codice in base al valore di un'espressione. - La forma tradizionale di
switch
è ampiamente utilizzata e funziona in tutti gli ambienti di sviluppo Java. - L'istruzione
switch
può essere utilizzata con tipi primitivi comeint
,char
,byte
,short
, e ora anche conString
. - L'istruzione
switch
può essere annidata e le istruzionicase
possono essere raggruppate senza l'uso dibreak
per eseguire lo stesso blocco di codice.
Istruzione switch
L'istruzione switch
è l'istruzione condizionale multipla di Java.
Fornisce un modo semplice per indirizzare l'esecuzione a parti diverse del codice in base al valore di un'espressione. In tal modo, spesso rappresenta un'alternativa migliore rispetto a una lunga serie di istruzioni if-else-if
.
All'inizio è opportuno precisare che, a partire da JDK 14, lo switch
è stato notevolmente potenziato ed esteso con diverse nuove funzionalità che vanno ben oltre la sua forma tradizionale.
La forma tradizionale di switch
è presente in Java fin dall'inizio ed è quindi ampiamente utilizzata. Inoltre, è la forma che funziona in tutti gli ambienti di sviluppo Java e per tutti le versioni del JDK.
A causa della rilevanza delle recenti estensioni dello switch
, tali miglioramenti sono descritti nelle lezioni future, nel contesto di altre aggiunte recenti a Java. Qui viene esaminata la forma tradizionale dello switch
.
Di seguito è mostrata la forma generale di un'istruzione switch
tradizionale:
switch (espressione) {
case valore1:
// sequenza di istruzioni
break;
case valore2:
// sequenza di istruzioni
break;
.
.
.
case valoreN:
// sequenza di istruzioni
break;
default:
// sequenza di istruzioni di default
}
Per le versioni di Java precedenti a JDK 7, espressione
deve risolvere a un tipo byte
, short
, int
, char
o a un'enumerazione (vedremo le enumerazioni più avanti).
Oggi, espressione
può anche essere di tipo String
. Ogni valore specificato nelle istruzioni case
deve essere un'espressione costante univoca (ad esempio un valore letterale). I valori duplicati nei case
non sono consentiti. Il tipo di ogni valore deve essere compatibile con il tipo di espressione
.
L'istruzione switch
tradizionale funziona in questo modo: il valore di espressione
viene confrontato con ciascuno dei valori nelle istruzioni case
. Se viene trovato un riscontro, viene eseguita la sequenza di codice che segue tale case
. Se nessuno dei valori corrisponde al valore di espressione
, viene eseguita l'istruzione default
. Tuttavia, default
è facoltativa. Se non vi sono corrispondenze e non è presente default
, non viene intrapresa alcuna azione.
L'istruzione break
viene utilizzata all'interno dello switch
per terminare una sequenza di istruzioni. Quando si incontra un break
, l'esecuzione passa alla prima riga di codice che segue l'intero switch
. Ciò ha l'effetto di “saltare fuori” dallo switch
.
Ecco un semplice esempio che utilizza un'istruzione switch
:
// Un semplice esempio dello switch.
class EsempioSwitch {
public static void main(String[] args) {
for (int indice = 0; indice < 6; indice++)
switch (indice) {
case 0:
System.out.println("indice è zero.");
break;
case 1:
System.out.println("indice è uno.");
break;
case 2:
System.out.println("indice è due.");
break;
case 3:
System.out.println("indice è tre.");
break;
default:
System.out.println("indice è maggiore di 3.");
}
}
}
L'output prodotto da questo programma è il seguente:
indice è zero.
indice è uno.
indice è due.
indice è tre.
indice è maggiore di 3.
indice è maggiore di 3.
Come si può osservare, a ogni iterazione del ciclo vengono eseguite le istruzioni associate alla costante case
che corrisponde a indice
. Tutte le altre vengono saltate. Quando indice
è maggiore di 3, nessuna istruzione case
corrisponde, quindi viene eseguito default
.
L'istruzione break
è facoltativa. Se viene omessa, l'esecuzione continua nel case
successivo. Talvolta è utile avere più case
senza istruzioni break
intermedie. Ad esempio, si consideri il programma seguente:
// In uno switch, le istruzioni break sono facoltative.
class BreakMancante {
public static void main(String[] args) {
for (int indice = 0; indice < 12; indice++)
switch (indice) {
case 0:
case 1:
case 2:
case 3:
case 4:
System.out.println("indice è minore di 5");
break;
case 5:
case 6:
case 7:
case 8:
case 9:
System.out.println("indice è minore di 10");
break;
default:
System.out.println("indice è 10 o più");
}
}
}
Questo programma genera il seguente output:
indice è minore di 5
indice è minore di 5
indice è minore di 5
indice è minore di 5
indice è minore di 5
indice è minore di 10
indice è minore di 10
indice è minore di 10
indice è minore di 10
indice è minore di 10
indice è 10 o più
indice è 10 o più
Si nota come l'esecuzione cada attraverso ogni case
finché non viene raggiunta un'istruzione break
(o la fine dello switch
).
Sebbene l'esempio precedente sia ovviamente costruito a scopo illustrativo, l'omissione di break
ha molte applicazioni pratiche nei programmi reali. Un esempio più realistico è la seguente riscrittura del programma sulle stagioni visto in precedenza, che utilizza uno switch
per un'implementazione più efficiente:
// Una versione migliorata del programma sulle stagioni.
class Interruttore {
public static void main(String[] args) {
int mese = 4;
String stagione;
switch (mese) {
case 12:
case 1:
case 2:
stagione = "Inverno";
break;
case 3:
case 4:
case 5:
stagione = "Primavera";
break;
case 6:
case 7:
case 8:
stagione = "Estate";
break;
case 9:
case 10:
case 11:
stagione = "Autunno";
break;
default:
stagione = "Mese non valido";
}
System.out.println("Aprile è in " + stagione + ".");
}
}
È anche possibile utilizzare una stringa per controllare un'istruzione switch
. Ad esempio:
// Utilizzare una stringa per controllare uno switch.
class SwitchStringa {
public static void main(String[] args) {
String stringa = "due";
switch (stringa) {
case "uno":
System.out.println("uno");
break;
case "due":
System.out.println("due");
break;
case "tre":
System.out.println("tre");
break;
default:
System.out.println("nessuna corrispondenza");
break;
}
}
}
Come previsto, l'output del programma è
due
La stringa contenuta in stringa
(che in questo programma è “due”) viene confrontata con le costanti case
. Quando si trova una corrispondenza (come accade nel secondo case
), viene eseguita la sequenza di codice associata.
La possibilità di utilizzare stringhe in un'istruzione switch
semplifica molte situazioni; ad esempio, uno switch
basato su stringhe rappresenta un miglioramento rispetto a una sequenza equivalente di istruzioni if/else
. Tuttavia, lo switch su stringhe può essere più costoso rispetto allo switch su interi. Pertanto è consigliabile utilizzare lo switch su stringhe solo quando i dati di controllo sono già in forma di stringa. In altre parole, evitare l'uso di stringhe in uno switch
quando non è necessario.
Istruzioni switch
annidate
È possibile usare uno switch
come parte della sequenza di istruzioni di uno switch esterno. Questo è chiamato switch
annidato. Poiché un'istruzione switch
definisce il proprio blocco, non sorgono conflitti tra le costanti case
nello switch
interno e quelle nello switch
esterno. Ad esempio, il seguente frammento è perfettamente valido:
switch (conteggio) {
case 1:
switch (bersaglio) { // switch annidato
case 0:
System.out.println("bersaglio è zero");
break;
case 1: // nessun conflitto con lo switch esterno
System.out.println("bersaglio è uno");
break;
}
break;
case 2: // ...
}
In questo caso, l'istruzione case 1:
nello switch
interno non confligge con l'istruzione case 1:
nello switch
esterno. La variabile conteggio
viene confrontata solo con l'elenco dei case al livello esterno. Se conteggio
vale 1, allora bersaglio
viene confrontato con i case dell'elenco interno.
In sintesi, vi sono tre caratteristiche importanti dello switch
da notare:
- Lo
switch
differisce dall'if
in quantoswitch
può testare solo l'uguaglianza, mentreif
può valutare qualsiasi tipo di espressione booleana. Vale a dire, loswitch
verifica solo la corrispondenza tra il valore dell'espressione e una delle sue costanticase
. - Nessuna delle costanti
case
nello stessoswitch
può avere valori identici. Naturalmente, un'istruzioneswitch
e unoswitch
esterno che la racchiude possono avere costanticase
in comune. - Un'istruzione
switch
è di solito più efficiente di un insieme diif
annidati.
L'ultimo punto è particolarmente interessante perché offre un'idea di come funziona il compilatore Java. Quando compila un'istruzione switch
, il compilatore ispeziona ciascuna delle costanti case
e crea una “tabella di salto” che utilizzerà per selezionare il percorso di esecuzione in base al valore dell'espressione. Pertanto, se occorre scegliere tra un ampio gruppo di valori, un'istruzione switch
verrà eseguita molto più rapidamente rispetto alla logica equivalente realizzata con una sequenza di if-else
. Il compilatore può farlo perché sa che tutte le costanti case
sono dello stesso tipo e devono semplicemente essere confrontate per uguaglianza con l'espressione dello switch
. Il compilatore non possiede tale conoscenza per un lungo elenco di espressioni if
.