Ein bisschen Theorie über switch in Java

Stell dir vor, du wärst ein Ritter, der an einer Weggabelung stehen bleibt. Wenn du nach links gehst, wirst du dein Pferd verlieren. Wenn du nach rechts gehst, wirst du Wissen erlangen. Wie würden wir diese Situation in Code darstellen? Du weißt wahrscheinlich schon, dass wir Konstrukte wie if-then und if-then-else verwenden, um diese Entscheidungen zu treffen.

if (turn_left) { 
    System.out.println("You will lose your horse"); 
}
if (turn_right) {
    System.out.println("You will gain knowledge");
}
else 
    System.out.println("So you're just going to stand there?");

Aber was ist, wenn sich die Straße nicht in zwei, sondern in zehn Teile gabelt? Du hast Straßen „ganz rechts“, „etwas links davon“, „ein bisschen weiter links“ und so weiter, insgesamt also 10 mögliche Straßen? Stell dir vor, wie dein if-then-else-Code in dieser Version anwachsen wird!

if (option1)
{…}
else if (option2)
{…}
…
else if (optionN) ...
Angenommen, du hast eine Weggabelung mit 10 Möglichkeiten (es ist wichtig, dass die Anzahl der Optionen endlich ist). Für solche Situationen gibt es in Java die switch-Anweisung.

       switch (ExpressionForMakingAChoice) {
           case (Value1):
               Code1;
               break;
           case (Value2):
               Code2;
               break;
...
           case (ValueN):
               CodeN;
               break;
           default:
               CodeForDefaultChoice;
               break;
       }

So funktioniert die Anweisung:
  • ExpressionForMakingAChoice wird ausgewertet. Dann vergleicht die switch-Anweisung den resultierenden Wert mit dem nächsten ValueX (in der Reihenfolge, in der sie aufgelistet sind).
  • Wenn ExpressionForMakingAChoice mit ValueX übereinstimmt, dann wird der Code nach dem Doppelpunkt ausgeführt.
  • Wenn eine break-Anweisung auftaucht, wird die Kontrolle an außerhalb der Switch-Anweisung übertragen.
  • Wenn ExpressionForMakingAChoice mit keinem ValueX übereinstimmt, wird die Kontrolle an CodeForDefaultCase übergeben.
Wichtige Hinweise:
  • In der switch-Anweisung muss der Typ von ExpressionForMakingAChoice einer der folgenden sein:

    • byte, short, char, int.
    • Byte, Short, Character, Integer (Wrapper der primitiven Datentypen).
    • String.
    • Enum.
  • Der default-Block ist optional. Wenn er nicht vorhanden ist und ExpressionForMakingAChoice mit keinem ValueX übereinstimmt, wird keine Aktion ausgeführt.

  • Die break-Anweisung ist nicht erforderlich. Fehlt er, wird der Code weiter ausgeführt (ohne weitere Vergleiche in den case-Anweisungen), bis zum ersten Auftreten von break oder bis zum Ende der switch-Anweisung.

  • Wenn derselbe Code für mehrere Auswahlmöglichkeiten ausgeführt werden muss, können wir Doppelungen vermeiden, indem wir mehrere aufeinanderfolgende case-Anweisungen angeben.

Schauen wir uns nun an, wie die switch-Anweisung in Java verwendet wird

Keine Sorge: Wir sind mit der Theorie fertig. Nachdem du die folgenden Beispiele gesehen hast, wird alles viel klarer. Also, fangen wir an. Schauen wir uns ein Beispiel aus der Astronomie an, bei dem es um die Planeten unseres Sonnensystems geht. In Übereinstimmung mit den neuesten internationalen Übereinkünften haben wir Pluto (aufgrund der Eigenschaften seiner Umlaufbahn) ausgeschlossen. Wir erinnern uns, dass unsere Planeten nach ihrem Abstand zur Sonne wie folgt angeordnet sind: Merkur, Venus, Erde, Mars, Jupiter, Saturn, Uranus und Neptun. Schreiben wir eine Java-Methode, die die Ordnungszahl eines Planeten (relativ zu seiner Entfernung von der Sonne) entgegennimmt und die Hauptbestandteile der Atmosphäre des Planeten als List<String> zurückgibt . Du wirst dich erinnern, dass einige Planeten eine ähnliche atmosphärische Zusammensetzung haben. So enthalten Venus und Mars hauptsächlich Kohlendioxid, die Atmosphäre von Jupiter und Saturn besteht aus Wasserstoff und Helium, und Uranus und Neptun ergänzen dieses Paar noch um Methan. Hier ist unsere Funktion:

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;
}
Beachte, dass wir den gleichen Code für Planeten mit identischer atmosphärischer Zusammensetzung verwenden. Dazu haben wir aufeinanderfolgende case-Anweisungen eingesetzt. Wenn wir die Zusammensetzung der Atmosphäre unseres Heimatplaneten erfahren wollen, rufen wir unsere Methode mit 3 als Argument auf:

getPlanetAtmosphere(3).
System.out.println(getPlanetAtmosphere(3)) returns ["Carbon dioxide", "Nitrogen", "Oxygen"].
Experimentiere mit break: Was passiert, wenn wir alle break-Anweisungen entfernen? Probieren wir es aus:

    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;
    }
Wenn wir das Ergebnis von System.out.println(getPlanetAtmosphere(3)) ausgeben, stellen wir fest, dass unser Heimatplanet nicht besonders lebenswert ist. Oder vielleicht doch? Urteile selbst:
["Kohlendioxid", "Stickstoff", "Sauerstoff", "Wasserstoff", "Helium", "Methan", "Wasserstoff", "Helium"].
Was ist hier passiert? Das Programm führt alle case-Anweisungen nach der ersten Übereinstimmung bis zum Ende des switch-Blocks aus.

Übermäßige Optimierung von break-Anweisungen

Beachte, dass wir die Methode verbessern können, indem wir die break- und case-Anweisungen anders anordnen.

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;
}
Sieht nach weniger Code aus, oder? Wir haben die Gesamtzahl der Anweisungen reduziert, indem wir mit der Reihenfolge der case-Anweisungen gespielt und sie neu gruppiert haben. Jetzt wird jedes Gas in nur einer Codezeile zur Liste hinzugefügt. Der Code im letzten Beispiel soll nur zeigen, wie die Dinge funktionieren. Wir raten davon ab, Code auf diese Weise zu schreiben. Wenn der Autor eines solchen Java-Codes (ganz zu schweigen von anderen Programmierern) diesen pflegen muss, wird es für ihn oder sie sehr schwierig sein, die Logik hinter der Bildung dieser case-Blöcke und dem in der switch-Anweisung ausgeführten Code zu rekonstruieren.

Unterschiede zu if-Anweisungen

Angesichts der äußerlichen Ähnlichkeiten von if- und switch-Anweisungen darfst du nicht vergessen, dass die switch-Anweisung einen der Fälle auf der Grundlage eines BESTIMMTEN WERTES auswählt, während die if-Anweisung einen beliebigen booleschen Ausdruck haben kann. Behalte dies bei der Gestaltung deines Codes im Hinterkopf. Java switch-Anweisung - 1

Fazit

  • Verwende die case-Anweisung für mehr als zwei Verzweigungen, um deinen Code nicht mit if-Anweisungen zu überladen.

  • Vergiss nicht, den logischen Block der Verzweigung für jeden bestimmten Wert (case-Anweisung) durch Einfügen einer break-Anweisung abzuschließen.

  • Der Ausdruck der switch-Anweisung kann ein Enum oder String sein, aber auch einige primitive Typen.

  • Vergiss auch nicht den default-Block. Verwende diesen, um unerwartete Werte zu behandeln.

  • Um die Leistung zu optimieren, solltest du die Codezweige, die den am häufigsten auftretenden Werten entsprechen, an den Anfang des switch-Blocks verschieben.

  • Übertreibe es nicht mit deiner „Optimierung“, indem du die break-Anweisungen am Ende der case-Anweisungen löschst – ein solcher Code ist schwer zu verstehen und daher auch schwer zu warten.