W3docs

Espressioni switch in Java

Espressioni switch moderne in Java con sintassi a freccia, yield e pattern matching esaustivo.

Java 14 ha promosso le espressioni switch a funzionalità standard del linguaggio. Si basano sull'istruzione switch tradizionale con tre importanti miglioramenti: producono un valore, utilizzano una sintassi a freccia più pulita e rendono impossibile il fall-through. Se stai usando Java 14 o versioni successive, preferiscile.

Questo capitolo tratta la sintassi a freccia, la parola chiave yield per i corpi a blocco, il controllo di esaustività e il pattern matching basato sul tipo diventato standard in Java 21. Al termine saprai quando ricorrere a un'espressione switch invece di una catena if/else.

Istruzione vs. espressione

Il switch tradizionale è un'istruzione: fa qualcosa (esegue effetti collaterali) ma non produce un valore. Un'espressione switch invece restituisce un valore che puoi assegnare, ritornare o passare a un metodo. Questa singola differenza guida tutto il resto in questa pagina — poiché il risultato viene utilizzato, il compilatore può esigere che ogni ramo produca un valore e che nessun input passi inosservato.

Sintassi a freccia

String day = "TUE";

String label = switch (day) {
  case "MON", "TUE", "WED", "THU", "FRI" -> "weekday";
  case "SAT", "SUN" -> "weekend";
  default -> "unknown";
};

Tre cose da notare:

  1. L'intero switch è un'espressione — restituisce un valore che puoi assegnare (nota il ; finale).
  2. Ogni case usa -> invece di :. Il lato destro è un'istruzione o espressione singola.
  3. Sono consentite più etichette in un case, separate da virgola. Nessun break, nessun fall-through.

Corpi a blocco con yield

Se un case richiede più istruzioni, usa un blocco — e all'interno del blocco restituisci il valore con yield:

int score = 78;

String grade = switch (score / 10) {
  case 10, 9 -> "A";
  case 8 -> "B";
  case 7 -> {
    System.out.println("close to B");
    yield "C";
  }
  case 6 -> "D";
  default -> "F";
};

yield è come return, ma per l'espressione switch — imposta il valore di questo switch ed esce dal case. (Non confonderlo con return, che uscirebbe dal metodo contenitore.)

Hai bisogno di yield solo all'interno di un blocco ({ ... }). Un case a espressione singola come case 8 -> "B"; restituisce già il suo valore direttamente, quindi aggiungere yield lì sarebbe un errore di compilazione.

Informazione

yield è una parola chiave contestuale: agisce come parola chiave solo all'interno di un blocco switch. Il codice che usava yield come nome di variabile o metodo prima di Java 14 continua a compilarsi, quindi adottare le espressioni switch non rompe mai gli identificatori esistenti.

Le istruzioni funzionano ancora

Puoi usare la sintassi a freccia anche per gli effetti collaterali, nel qual caso è un'istruzione e non un'espressione:

switch (day) {
  case "MON", "TUE", "WED", "THU", "FRI" -> System.out.println("weekday");
  case "SAT", "SUN" -> System.out.println("weekend");
  default -> System.out.println("unknown");
}

Il vantaggio rispetto alla vecchia forma: nessun break, nessun bug da fall-through, più i case a più etichette visti sopra.

Esaustività

Quando un'espressione switch assegna a una variabile, il compilatore richiede che ogni possibile input produca un valore. Per un enum, ciò significa coprire tutte le costanti o fornire un default:

enum Status { PENDING, ACTIVE, DONE }

Status s = Status.ACTIVE;

String label = switch (s) {
  case PENDING -> "waiting";
  case ACTIVE  -> "running";
  case DONE    -> "complete";
};   // no default needed — all enum values are covered

Se in seguito aggiungi una nuova costante all'enum e dimentichi di aggiornare lo switch, il compilatore te lo dirà. Questa è una forte garanzia di correttezza che non ottieni con if/else.

Pattern matching (Java 21+)

Java 21 ha reso il pattern matching per switch una funzionalità standard. Puoi fare lo switch sul tipo di un valore e associarlo a una variabile tipizzata all'interno del case:

Object o = 42;

String description = switch (o) {
  case Integer i when i < 0 -> "negative int: " + i;
  case Integer i             -> "non-negative int: " + i;
  case String s              -> "string of length " + s.length();
  case null                  -> "null value";
  default                    -> "something else";
};

La clausola when è una guardia — restringe ulteriormente un case con una condizione booleana. Questo sostituisce molte catene instanceof e si abbina naturalmente alle funzionalità più ampie di pattern matching.

Due regole da tenere a mente:

  • Un switch tradizionale rifiuta un selettore null con una NullPointerException. Un pattern switch può includere un esplicito case null — senza di esso, un null genera ancora un'eccezione. Non è più possibile ignorare silenziosamente un null che raggiunge lo switch.
  • I case vengono testati dall'alto verso il basso, quindi ordina dal più specifico al più generale. Il case Integer i when i < 0 con guardia deve venire prima del semplice case Integer i, altrimenti il case senza guardia ingoierebbe ogni intero per primo.

Esempio pratico

java— editable, runs on the server

Cosa c'è dopo

Abbiamo trattato i condizionali. Ora arrivano i cicli: il ciclo while è il più semplice di tutti.

Esercitazione

Pratica
In un'espressione switch a freccia con un corpo a blocco, quale parola chiave restituisce il valore di quel case?
In un'espressione switch a freccia con un corpo a blocco, quale parola chiave restituisce il valore di quel case?
Was this page helpful?