JavaRush /Java Blog /Random-IT /Cambia istruzione in Java

Cambia istruzione in Java

Pubblicato nel gruppo Random-IT
Immagina di trovarti a un bivio, come l'eroe di un famoso dipinto. Se vai a sinistra perderai il cavallo; se vai a destra acquisirai conoscenza. Come programmare una situazione del genere? Molto probabilmente sai già che facciamo una scelta del genere usando i costrutti if-then e if-then-else .
if (turn_left) {
    System.out.println(«Коня потеряешь»);
}
if (turn_right) {
    System.out.println(“Знания обретёшь”);
}
else
    System.out.println(“Так и будешь стоять?);
E se non ci fossero due di queste tracce, ma 10? Esiste un percorso “a destra”, “un po' a sinistra”, “un po' più a sinistra” e così via, per un totale di 10 pezzi? Immagina come crescerà il tuo codice if-then-else in questa versione!
if (вариант1)
{}
else if (вариант2)
{}else if (вариантN).
Quindi non hai un fork di condizioni, ma diversi, diciamo 10 (la cosa importante qui è che il numero di fork sia limitato). Per tali situazioni, esiste una speciale selezione dell'operatore - switch case java .
switch (ВыражениеДляВыбора) {
           case  (Значение1):
               Код1;
               break;
           case (Значение2):
               Код2;
               break;
...
           case (ЗначениеN):
               КодN;
               break;
           default:
               КодВыбораПоУмолчанию;
               break;
       }
L'ordine di esecuzione nella dichiarazione è il seguente:
  • Viene valutata la SelectionExpression. Successivamente, l'istruzione switch confronta l'espressione risultante con il valore successivo (nell'ordine elencato).
  • Se SelectExpression corrisponde a Value, viene eseguito il codice che segue i due punti.
  • Se viene incontrato il costrutto break , il controllo viene trasferito all'esterno del comando switch.
  • Se non vengono trovate corrispondenze tra ExpressionForSelection e Values, il controllo viene trasferito al DefaultSelectionCode.
Punti importanti
  • Il tipo SelectionExpression per un'istruzione di selezione switch in Java deve essere uno dei seguenti:

    • byte , breve , carattere , int .
    • I loro wrapper sono Byte , Short , Character , Integer .
    • Stringa (da Java 7).
    • Enumerazione ( Enum ).
  • Il blocco predefinito è facoltativo, quindi se SelectionExpression e Values ​​non corrispondono, non verrà eseguita alcuna azione.
  • break è facoltativo; se non è presente, il codice continuerà l'esecuzione (ignorando ulteriori confronti di valori nei blocchi case) fino alla prima breakistruzione switch incontrata o fino alla fine.
  • se è necessario eseguire lo stesso codice per più opzioni di selezione, per evitare duplicazioni indichiamo davanti ad esso più valori corrispondenti in blocchi case consecutivi .

Passiamo alla pratica dell'utilizzo dell'istruzione switch in Java

Non preoccuparti, abbiamo finito con la teoria e dopo ulteriori esempi tutto diventerà molto più chiaro. Quindi iniziamo. Diamo un'occhiata ad un esempio tratto dall'astronomia sui pianeti del sistema solare. In conformità con le ultime normative internazionali, escluderemo Plutone (a causa delle proprietà della sua orbita). Ricordiamo che i nostri pianeti si trovano a partire dal Sole nella seguente sequenza: Mercurio, Venere, Terra, Marte, Giove, Saturno, Urano e Nettuno. Creiamo un metodo Java che riceve come input il numero seriale del pianeta (relativo alla distanza dal Sole), e come output fornisce la composizione principale dell'atmosfera di questo pianeta sotto forma di List <String> . Lascia che ti ricordi che alcuni pianeti hanno una composizione atmosferica simile. Pertanto, Venere e Marte contengono principalmente anidride carbonica, Giove e Saturno sono costituiti da idrogeno ed elio e Urano e Nettuno, oltre all'ultima coppia di gas, contengono anche metano. La nostra funzione:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
    List<String> result = new ArrayList<>();
    switch (seqNumberFromSun) {
        case 1: result.add("No Atmosphere");
            break;
        case 2:
        case 4: result.add("Carbon dioxide");
            break;
        case 3: result.add("Carbon dioxide");
            result.add("Nitrogen");
            result.add("Oxygen");
            break;
        case 5:
        case 6: result.add("Hydrogen");
            result.add("Helium");
            break;
        case 7:
        case 8: result.add("Methane");
            result.add("Hydrogen");
            result.add("Helium");
            break;
        default:
            break;
    }
    return result;
}
Nota: abbiamo confrontato lo stesso codice con pianeti con identica composizione atmosferica. E lo abbiamo fatto utilizzando costruzioni di casi consecutivi . Quindi, se vogliamo ottenere la composizione dell'atmosfera del nostro pianeta natale, chiamiamo il nostro metodo con il parametro 3:
getPlanetAtmosphere(3).
System.out.println(getPlanetAtmosphere(3)) вернет нам [Углекислый газ, Азот, Кислород].
Sperimenta con break Cosa succede se rimuoviamo tutte le istruzioni break ? Proviamolo in pratica:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
    List<String> result = new ArrayList<>();
    switch (seqNumberFromSun) {
        case 1: result.add("No Atmosphere");
        case 2:
        case 4: result.add("Carbon dioxide");
        case 3: result.add("Carbon dioxide");
            result.add("Nitrogen");
            result.add("Oxygen");
        case 5:
        case 6: result.add("Hydrogen");
            result.add("Helium");
        case 7:
        case 8: result.add("Methane");
            result.add("Hydrogen");
            result.add("Helium");
        default:
    }
    return result;
}
Se stampiamo il risultato del metodo System.out.println(getPlanetAtmosphere(3)), il nostro pianeta natale non sarà così adatto alla vita. O adatto? Giudica tu stesso: [anidride carbonica, azoto, ossigeno, idrogeno, elio, metano, idrogeno, elio], perché è successo? Il programma ha eseguito tutti i casi dopo la prima corrispondenza e fino alla fine del blocco di commutazione.

Interruzione eccessiva dell'ottimizzazione

Si noti che possiamo migliorare il metodo con una diversa disposizione delle direttive di interruzione e delle opzioni di selezione
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
    List<String> result = new ArrayList<>();
    switch (seqNumberFromSun) {
        case 1: result.add("No Atmosphere");
                break;
        case 3: result.add("Nitrogen");
                result.add("Oxygen");
        case 2:
        case 4: result.add("Carbon dioxide");
                break;
        case 7:
        case 8: result.add("Methane");
        case 5:
        case 6: result.add("Hydrogen");
                result.add("Helium");
    }
     return result;
}
Sembra più corto, vero? Abbiamo ridotto il numero totale di dichiarazioni giocando con l'ordine dei casi e raggruppandoli. Ora ogni tipo di gas viene aggiunto all'elenco in una sola riga di codice. L'elenco dell'ultimo esempio del metodo viene mostrato solo per dimostrare il lavoro; è altamente sconsigliato scrivere in questo stile. Se l'autore (e ancor più i programmatori di terze parti) di un codice simile deve mantenerlo, sarà molto difficile ripristinare la logica per la formazione dei blocchi di selezione e del codice eseguibile per l'istruzione java switch.

Differenze da se

Anche se le istruzioni if ​​e switch hanno un aspetto simile , non dimenticare che l'operatore a scelta multipla switch basa la scelta delle opzioni di esecuzione su un VALORE SPECIFICO, mentre in if. può essere qualsiasi espressione logica. Tieni presente questo fatto quando progetti il ​​tuo codice. Diamo uno sguardo più da vicino alle innovazioni per il passaggio alle diverse versioni di Java.

Passa a Java 7

Prima di Java 7, le primitive byte, short, char e int potevano essere utilizzate come valore per uno switch. C'era anche il supporto per enum e wrapper dei tipi primitivi elencati sopra: Character, Byte, Short e Integer. Ma spesso abbiamo bisogno di trovare il valore di una stringa di switch Java! Questo è come sarebbe in Java 6:
DayOfWeek day = DayOfWeek.fromValue("Thursday");

switch (day) {
  case MONDAY:
     System.out.println("Today is windy !");
     break;
  case THURSDAY:
     System.out.println("Today is sunny !");
     break;
  case WEDNESDAY:
     System.out.println("Today is rainy!");
     break;
  default:
     System.out.println("Oooops, something wrong !");
Ed enumerare:
public enum DayOfWeek {
  MONDAY("Monday"),
  THURSDAY("Thursday"),
  WEDNESDAY("Wednesday"),
  NOT_FOUND("Not found");

  private final String value;

  DayOfWeek(final String value) {
     this.value = value;
  }

  public static DayOfWeek fromValue(String value) {
     for (final DayOfWeek dayOfWeek : values()) {
        if (dayOfWeek.value.equalsIgnoreCase(value)) {
           return dayOfWeek;
        }
     }
     return NOT_FOUND;
  }
}
Ma a partire da Java 7, era possibile utilizzare il tipo String come valore per uno switch:
String day = "Thursday";

switch (day) {
  case "Monday":
     System.out.println("Today is windy !");
     break;
  case "Thursday":
     System.out.println("Today is sunny !");
     break;
  case "Wednesday":
     System.out.println("Today is rainy!");
     break;
  default:
     System.out.println("Oooops, something wrong !");
}
Nonostante le nuove funzionalità, l'approccio utilizzando enum è più flessibile ed è consigliato per l'uso: possiamo riutilizzare questa enum molte volte.

Passa a Java 12

Java 12 ha migliorato le espressioni Switch per la corrispondenza dei modelli. Se usiamo Switch come nell'esempio sopra, per impostare il valore di qualche variabile, dobbiamo calcolare il valore e assegnarlo alla variabile data, quindi usare break:
int count = 2;
int value;
switch (count) {
  case 1:
     value = 12;
     break;
  case 2:
     value = 32;
     break;
  case 3:
     value = 52;
     break;
  default:
     value = 0;
}
Ma grazie alle funzionalità di Java 12, possiamo riscrivere questa espressione come segue:
int value = switch (count) {
  case 1:
     break 12;
  case 2:
     break 32;
  case 3:
     break 52;
  default:
     break 0;
};
Esaminiamo un po' le modifiche:
  1. Se prima impostavamo un valore variabile all'interno dei blocchi case, poiché l'istruzione switch stessa non poteva restituire nulla, ora abbiamo questa opportunità e restituiamo direttamente il valore utilizzando switch.

  2. Prima non potevamo più avere nulla a destra di break, ma ora lo usiamo come istruzione return per restituire il valore del nostro switch. I due punti contrassegnano il punto di ingresso in un blocco di istruzioni. Cioè da quel punto inizia l'esecuzione di tutto il codice seguente, anche quando viene incontrata un'altra etichetta.

    Il risultato è una transizione end-to-end da boa a boa, chiamata anche fall -through.

Istruzione Switch in Java - 2Per completare un passaggio di questo tipo, è necessario esaminare completamente tutti gli elementi oppure utilizzare break o return. L'innovazione in Java 12 ci dà la possibilità di utilizzare l'operatore lambda, che a sua volta garantisce che venga eseguito solo il codice alla sua destra. Senza alcun "fallimento". Come sarà l'esempio precedente in questo caso:
int count = 2;
int value = switch (count) {
  case 1 -> 12;
  case 2 -> 32;
  case 3 -> 52;
  default -> 0;
};
Il codice è diventato molto più semplice, vero? E ancora una cosa: l'operatore lambda può anche servire come un tipico analogo dei due punti, dopo di che c'è un intero blocco con alcune operazioni:
int count = 2;
int value = switch (count) {
  case 1 -> {
     //some computational operations...
     break 12;
  }
  case 2 -> {
     //some computational operations...
     break 32;
  }
  case 3 -> {
     //some computational operations...
     break 52;
  }
  default -> {
     //some computational operations...
     break 0;
  }
};
Bene, cosa succederebbe se in alcuni casi il valore restituito fosse lo stesso? Si scopre che in realtà abbiamo gli stessi casi per alcuni valori diversi. Ecco come questo potrebbe essere abbreviato utilizzando le nuove funzionalità di Java 12:
int count = 2;
int value = switch (count) {
  case 1, 3, 5 -> 12;
  case 2, 4, 6 -> 52;
  default -> 0;
};

Passa a Java 13

In Java 13, il modo in cui uno switch restituisce un valore è cambiato. Se in Java 12 scrivevamo il valore di ritorno dopo break, che ci serviva da return per il blocco switch, ora restituiremo il valore utilizzando la parola yield . Guardiamo:
int value = switch (count) {
  case 1:
     yield 12;
  case 2:
     yield 32;
  case 3:
     yield 52;
  default:
     yield 0;
};
Allo stesso tempo, il codice scritto in Java 12 utilizzando break per return non verrà compilato (( Istruzione Switch in Java - 3Verrà utilizzato Break, ma in situazioni in cui non è necessario restituire nulla.

Totale

  • Utilizzare l' istruzione case quando sono presenti più di due rami per evitare di ingombrare il codice con strutture if.
  • Non dimenticare di terminare il blocco logico di ciascun ramo corrispondente ad un valore specifico (blocco case) con una chiamata di interruzione .
  • Oltre ad alcuni tipi primitivi, l'istruzione switch può utilizzare anche i tipi Enum e String come espressioni .
  • Ricorda il blocco predefinito : usalo per gestire valori di selezione non pianificati.
  • Per ottimizzare le prestazioni, spostare i rami di codice con le scelte più comuni all'inizio del blocco di interruttori.
  • Non lasciarti trasportare dall'"ottimizzazione" rimuovendo l'interruzione alla fine del blocco di selezione dei casi : tale codice è difficile da comprendere e, di conseguenza, difficile da mantenere durante il suo sviluppo.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION