Ciao a tutti e bentornati!
Dopo una pausa, torniamo oggi con un'altra parte del corso introduttivo alla programmazione, parlando di switch statement, conosciuto anche come costrutto di selezione multipla.
Intuizione
L'idea dello switch statement nasce da un problema che vediamo adesso.
Il problema è quello di cercare un modo comodo per evitare lunghe catene di if-elseif-else. Cerchiamo di rendere un po' più concreta questa situazione. Ipotizziamo di voler realizzare un menù ad interfaccia testuale con una ventina di opzioni, che dovrà richiedere all'utente di effettuare una scelta ed eseguire le operazioni corrispondenti alla scelta effettuata. Ci si trova quindi a vedere su schermo una cosa simile alla seguente:
1. Scelta 1
2. Scelta 2
...
Il modo più immediato di gestire questa situazione, potrebbe essere, per l'appunto, una lunga serie di if-elseif-else, scrivendo una porzione di codice simile alla seguente:
if(scelta == 1){
//fai qualcosa
}else if(scelta == 2){
//fai qualcos'altro
}
...
else{
//fai qualcos'altro ancora
}
Il problema di questo primo approccio si rende ben visibile quando le possibili scelte sono davvero molte. Il codice diventa molto lungo, e soprattutto di difficile lettura. Questo, alla lunga, può diventare un problema, soprattutto se non siamo le uniche persone a doverci occupare del prodotto su cui stiamo lavorando.
È evidente il fatto che, con gli strumenti attuali, non siamo in grado di scrivere del codice migliore rispetto a quello presentato prima. Diventa quindi necessario introdurre un nuovo strumento: lo switch.
Lo switch case
Come per tutti gli altri strumenti che ho introdotto in precedenza, andiamo prima di tutto a vedere com'è composto a livello sintattico.
Sintassi
Vediamo a livello sintattico com'è composto questo costrutto.
variabileCheRappresentaLaScelta
switch(variabileCheRappresentaLaScelta){
case valoreUno:
break;
case valoreDue:
break;
....
default:
}
Tipo del parametro
Prima di effettuare una disamina relativa al funzionamento dello switch-case , è d'obbligo sottolineare che il parametro dello switch deve essere una espressione (o variabile) di tipo byte , short , char , int oppure Enum (vedremo più avanti di cosa si tratta). Dalla versione 7 di Java, viene contemplato anche il tipo String.
Questo significa che i valori nelle clausole case (valoreUno, valoreDue, ...) devono essere del medesimo tipo del parametro (variabileCheRappresentaLaScelta).
Interpretazione semantica
L'interpretazione dello switch case è leggermente più complicata rispetto a quella dell'if-elseif-else. Come suggeriscono gli amici di html.it, può essere comodo leggere il codice come segue:
“dato un valore per variabileCheRappresentaLaScelta, procedi ad eseguire le istruzioni a partire dal
casecontrassegnato dallo stesso valore”.
La parte critica di questa interpretazione è proprio quella dell'a partira da. Significa proprio che viene effettuato un salto al case del valore corrispondente, ignorando completamente tutti gli altri case.
Vi è inoltre il caso di default case, che viene eseguito se e solo se nessuno dei case precedenti è soddisfatto. Questo case è assolutamente opzionale. Se lo omettiamo, dobbiamo essere coscienti del fatto che nessun'operazione verrà eseguita se nessuno dei case è soddisfatto. Generalmente, questo è un male perchè è bene che venga restituito all'utente un messaggio di errore in questo caso.
L'istruzione break
Iniziamo con una premessa. Questo è l'unico caso contemplato dalla programmazione strutturata dove è concesso utilizzare l'istruzione break.
Tecnicamente, il break non fa parte del costrutto in sè, ma viene usato in connessione ad esso ed è opzionale.
L'istruzione break è un'istruzione del linguaggio e serve a terminare l'esecuzione di un blocco di programma. Volendo essere più precisi, serve a terminare un blocco associato ad un ciclo o ad uno switch.
La domanda che ci si può porre è: "cosa succede se ometto il break?".
Succede che i case vengono eseguiti in sequenza fino a quando non si trova un break o fino a quando non si giunge al termine dello switch.
Esempio
Il primo, semplice esempio che vediamo è quello dove vogliamo restituire all'utente la trascrizione in lettere di un numero inserito. Chiaramente, dovendo scrivere un numero finito di case dovremo stabilire un range e di conseguenza definire il case dove restituiremo un qualche messaggio di errore nel caso in cui il numero inserito dall'utente non sia nel range.
Vedremo in seguito le istruzioni per richiedere un input all'utente, per cui simuleremo l'input dell'utente assegnando nel codice un valore ad una variabile.
Analizziamo subito il codice.
public class Main{
public static void main(String[] args){
int numero = n;
switch(numero){
case 1:
System.out.println("Uno");
break;
case 2:
System.out.println("Due");
break;
case 3:
System.out.println("Tre");
break;
default:
System.out.println("Out of range");
}
}
}
Vediamo bene che l'esempio ricalca a pieno la sintassi che ho fornito prima. Se la variabile numero vale 1, allora stamperà a schermo la stringa "Uno" e via dicendo. È assolutamente necessario inserire l'istruzione di break dal momento in cui, se la omettessimo, verrebbero eseguiti tutti i case in sequenza fino al primo break se presente o fino al termine dello switch in alternativa.
Bisogna fare attenzione che questo sorgente, così com'è, non è funzionante. Alla terza riga, dove vediamo scritto int numero = n; dobbiamo rimuovere la n a destra dell'uguale e sostituire il valore vero e proprio. Questo è un modo un po' "rozzo" di simulare un input dell'utente, ma è più che sufficiente in questi casi, dove il focus deve essere l'apprendimento e non l'usabilità dell'applicazione.
Altro esempio
In questo altro esempio, vogliamo determinare se un determinato carattere è una vocale o una consonante. Vediamo come è possibile farlo. Prima di analizzare il codice, è bene precisare che userò una nuova feature introdotta con Java 12, ovvero la possibilità di contemplare più valori in uno stesso case.
Vediamo il frammento di codice dello switch.
public class Main{
public static void main(String[] args){
int numero = n;
switch(numero){
case 'a', 'e', 'i', 'o', 'u':
System.out.println("Vocale");
break;
default:
System.out.println("Consonante");
}
}
}
Vediamo come siano presenti due case, uno per le vocali e uno per le consonanti. L'intuizione è che se non eseguo il case relativo alle vocali, posso eseguire le istruzioni del default case per comunicare che il carattere è una consonante.
Anche per questa volta è tutto. Come sempre, vi invito a sperimentare ![]()