W3docs

L'istruzione switch in Java

Usa switch in Java per confrontare un valore con più casi, con etichette case, break, default e il comportamento fall-through.

Quando devi confrontare un singolo valore con molte possibilità, una lunga catena if/else if diventa rapidamente caotica. L'istruzione switch è l'alternativa compatta di Java — legge il valore una volta, salta al case corrispondente ed esegue il suo blocco.

Sintassi di base

switch (value) {
  case label1:
    // body
    break;
  case label2:
    // body
    break;
  default:
    // body
    break;
}

Un piccolo esempio:

int day = 3;

switch (day) {
  case 1:
    System.out.println("Monday");
    break;
  case 2:
    System.out.println("Tuesday");
    break;
  case 3:
    System.out.println("Wednesday");
    break;
  default:
    System.out.println("Other");
    break;
}

Lo switch salta a case 3:, stampa Wednesday, incontra break ed esce.

Il break è essenziale

Senza break, l'esecuzione cade in avanti al caso successivo — anche se la sua etichetta non corrisponde. Questa è una funzionalità deliberata dello switch in stile C, ma è la fonte di innumerevoli bug nel codice Java:

switch (day) {
  case 1:
    System.out.println("Monday");
    // no break!
  case 2:
    System.out.println("Tuesday");
    break;
}

Quando day == 1, questo stampa sia Monday che Tuesday. Aggiungi sempre break a meno che tu non voglia intenzionalmente il fall-through.

Fall-through intenzionale

A volte il fall-through è esattamente quello che vuoi — raggruppare più etichette sotto lo stesso blocco:

switch (day) {
  case 1:
  case 2:
  case 3:
  case 4:
  case 5:
    System.out.println("Weekday");
    break;
  case 6:
  case 7:
    System.out.println("Weekend");
    break;
}

Quando lo fai intenzionalmente, aggiungi un commento // fall through affinché i revisori non pensino che tu abbia dimenticato un break. (La nuova sintassi delle switch expression — trattata nel prossimo capitolo — elimina completamente questo problema.)

Quali valori può accettare uno switch?

Un switch tradizionale accetta:

  • Tutti i tipi interi: byte, short, int, char
  • I loro wrapper boxed: Byte, Short, Integer, Character
  • String (da Java 7)
  • Costanti enum

Non sono ammessi: long, float, double, boolean o oggetti arbitrari. Per questi, usa if/else.

String role = "admin";

switch (role) {
  case "admin":
    System.out.println("Full access");
    break;
  case "editor":
    System.out.println("Write access");
    break;
  case "viewer":
    System.out.println("Read access");
    break;
  default:
    System.out.println("No access");
    break;
}

Il confronto tra stringhe in uno switch usa la semantica di String.equals — è sensibile alle maiuscole. Un punto critico: usare uno switch su una String (o qualsiasi valore boxed/enum) che è null lancia una NullPointerException. Controlla il null prima dello switch oppure gestiscilo in una guardia:

if (role == null) {
  System.out.println("No role");
} else {
  switch (role) {
    case "admin":
      System.out.println("Full access");
      break;
    // ...
  }
}

default — il caso generale

default viene eseguito quando nessun case corrisponde. Non è obbligatorio, ma includerlo è una buona pratica: rende esplicito il comportamento per valori inattesi.

default non deve necessariamente essere in fondo. Per convenzione va in basso, ma il compilatore lo accetta ovunque — l'esecuzione vi cade come in qualsiasi altro case se dimentichi break.

Regole da tenere a mente

Un paio di regole imposte dal compilatore possono sorprendere:

  • Le etichette case devono essere costanti note a tempo di compilazione. Puoi usare letterali (case 3:), costanti final o nomi di enum — ma non una variabile o una chiamata a metodo. case x: dove x è una variabile non-final non compila.
  • Le etichette devono essere univoche. Due voci case 3: nello stesso switch sono un errore di compilazione.
  • Tutti i case condividono un unico scope. Una variabile dichiarata in un case è visibile negli altri, il che può causare conflitti. Racchiudi il corpo di un case tra { } quando hai bisogno di una variabile locale con scope limitato a quel case:
switch (day) {
  case 1: {
    int hours = 8;
    System.out.println(hours);
    break;
  }
  case 2:
    // `hours` is not visible here
    break;
}

Switch su enum

enum e switch sono una coppia naturale. All'interno di uno switch su un valore enum, non devi qualificare il nome della costante:

enum Status { PENDING, ACTIVE, DONE }

Status s = Status.ACTIVE;

switch (s) {
  case PENDING:           // not Status.PENDING
    System.out.println("Waiting...");
    break;
  case ACTIVE:
    System.out.println("In progress");
    break;
  case DONE:
    System.out.println("Finished");
    break;
}

Un esempio pratico

java— editable, runs on the server

Cosa c'è dopo

Java 14 ha introdotto le switch expression, che restituiscono un valore, eliminano il fall-through e supportano case con più etichette — il codice Java moderno le preferisce quando si lavora con Java 14 o versioni successive.

Pratica

Pratica
In un tradizionale switch Java, cosa succede se si omette break in un blocco case?
In un tradizionale switch Java, cosa succede se si omette break in un blocco case?
Was this page helpful?