Du liest:
Das Switch Case in Java (mit Codebeispielen)

Das Switch Case in Java (mit Codebeispielen)

von Pero
25.05.2020
Die Java switch case Anweisung

Der standardmäßige Kontrollfluss in einem Java-Programm führt jede Anweisung nacheinander, von oben nach unten und in gerader Reihenfolge aus. Wenn keine Anweisungen mehr auszuführen sind, wird das Programm beendet. Es wäre ziemlich schwer komplexere Programme zu bauen, wenn wir nichts tun könnten, um den Kontrollfluss zu manipulieren. Zu unserem Vorteil bietet Java reichlich Möglichkeiten, um den Kontrollfluss nach unserem Wunsch zu steuern. Wir können mit Schleifen die gleiche Anweisung wiederholt ausführen oder mit Verzweigungen den Kontrollfluss an Bedingungen knüpfen.
Heute werden wir uns eines der populärsten Verzweigungsarten ansehen, das switch case in Java.

1. Die Grundlagen

Das switch-case Konstrukt ist ziemlich simpel aufgebaut und sieht in etwa so aus:

switch (zuÜberprüfendeElement) {
  case fallsEins: 
     // Anweisungen
  case fallsZwei: 
     // Anweisungen
  default: 
     // Standardanweisung, falls die ersten Beiden Verzweigungen falsch sind
} 

Das zuÜberprüfendeElement muss dabei entweder ein char, byte, short, int, enum (ab Java 6) oder String (ab Java 7) sein. Neben Strings und Enums kannst du nur Variablen benutzen deren Datentyp automatisch zu einem int vergrößert oder erweitert werden können. Alle anderen Datentypen würden zu einem Kompilierungsfehler führen.
Das bedeutet, dass deine Variable, die du der Anweisung übergibst, vom Datentyp weder ein long, float, double oder boolean sein darf.
Beim boolean sollte das kein Problem darstellen, da du dort mit einem if-else Konstrukt besser bedient bist.
Der switch-Block ist von geschweiften Klammern umgeben. In diesem Block kannst du dann den übergebenen Parameter durch case-Anweisungen auf bestimmte Bedingungen prüfen. Dabei musst du beachten, dass die case-Bedingungen vom gleichen Datentyp wie die zu überprüfende Variable ist.

Das folgende Codebeispiel wartet auf die Tastatureingabe eines Nutzers und wertet diese danach in einem Switch Case Java Statement aus.

Scanner scanner = new Scanner(System.in);
int zahlenBeispiel = scanner.nextInt();

switch (zahlenBeispiel) {
  case 0:
    // Anweisung falls zahlenBeispiel gleich 1 ist
  case 1:
    // Anweisung falls zahlenBeispiel gleich 2 ist
  case 2: 
    // Anweisung falls zahlenBeispiel gleich 3 ist
  default:
    // Standardanweisung, falls case 1, 2 & 3 falsch sind
}

Solang das übergebene Element und die Bedingungsdatentypen die gleichen sind, solltest du keine Probleme mit der Nutzung von dem Switch Case Konstrukt haben.
Es gibt jedoch paar Sachen, auf die du trotzdem achten musst!
Hier ein paar davon!

1.1. Nutzung von Variablen als Bedingung der Verzweigung

An sich spricht nichts gegen die Nutzung von Variablen als Bedingung für die jeweilige Verzweigung. Jedoch musst du beachten, dass die Variable final sein muss und der enthaltene Wert muss während der Kompilierung auflösbar sein. Das liegt daran, dass der Compiler die case-Variable während der Kompilierungszeit und nicht während der Laufzeit prüft! Es mag zwar für den Anfang ziemlich kompliziert klingen, aber folgendes Beispiel sollte das ganze ziemlich gut erläutern.

final int a = 1;
final int;

b = 2;

int test= 0;
switch (test) {
  case a: // in Ordnung
  case b: // NICHT in Ordnung => Kompilierungsfehler

Die Variable b kann während der Kompilierungszeit nicht aufgelöst werden, daher führt das Switch Konstrukt in diesem Falle zu einem Kompilierungsfehler.

1.2. Das Java Switch Case Konstrukt prüft nur auf Gleichheit!

Ein Fehler, den viele am Anfang machen, ist die Nutzung eines switch-case Block in Kombination mit Vergleichsoperatoren. Die case-Bedingungen prüft nur auf Gleichheit der Werte. Daher ist es nicht möglich Vergleichsoperatoren wie größer oder kleiner zu verwenden. Folgendes Beispiel ist demnach nicht möglich:

int test= 0;
switch (test) {
  case > a: 
  case < b:  
// GEHT NICHT!

1.3. Achte auf den Wertebereich von deinem Datentyp!

Eine Variable ist schnell deklariert und in einem switch-case Block genutzt, dennoch darfst du nie den Wertebereich des genutzten Datentypen aus den Augen verlieren!
Nehmen wir mal folgendes Beispiel, indem wir den Datentyp byte nutzen. Nochmal zur Erinnerung: ein byte hat einen Wertebereich von -127 bis +127.
Was denkst du wird passieren?

byte g = 2;

switch(g) {
  case 23:  // Das ist in Ordnung
  case 128: // Das nicht!
} 

Das Programm würde in diesem Falle einen Kompilierzeitfehler auswerfen, da die Bedingung außerhalb vom Wertebereich des Datentypen byte liegt.

1.4. Eine Bedingung darf sich nicht wiederholen!

Du kennst es selbst, umso länger das Programm wird umso mehr vergisst du was du eigentlich schonmal genutzt hast. Das darf dir allerdings nicht beim switch case passieren!

int geschwindigkeit = 100;

switch(geschwindigkeit) {
  case 100 : 
    System.out.println("100");
    break;
  case 100 : System.out.println("100"); // wird nicht kompilieren
    System.out.println("100");
    break;
  default : 
    System.out.println("Standardanweisung"); 
}

Das Programm würde in diesem Falle nicht kompilieren, da dort zwei case-Verzweigungen dieselbe Bedingung haben.

2. Das Schlüsselwort break

Wie du eventuell schon in den vorangegangenen Beispielen gemerkt hast, habe ich das break-Statement am Ende jeder case-Verzweigung platziert. Das liegt daran, dass die case-Verzweigungen von oben bis unten, vom Ersten bis zum Letzten und in der von dir geschriebenen Reihenfolge evaluiert werden. Es ist also wichtig in welcher Reihenfolge du die Verzweigungen schreibst! Der erste Treffer ist der ausschlaggebende und sobald dieser ausgelöst wurde, werden die Anweisungen in der jeweiligen Verzweigung ausgeführt.

Das hört sich ziemlich logisch und leicht zu merken an. Leider ist es nicht ganz so simpel, schauen wir uns mal folgendes Beispiel an:

class SwitchBeispiel {

  enum Farben {rot, gelb, blau}

  public static void main(String [] args) { 

    Farben c = Farben.gelb;

    switch(c) {
      case rot:
        System.out.print("rot ");
      case gelb:
        System.out.print("gelb ");
      case blau:
        System.out.print("blau ");
      default:
        System.out.println("fertig");
    }
  }
}

Wenn du denkst, dass gelb ausgegeben wird, liegst du richtig. Aber auch nicht ganz.
Nach gelb wird auch noch blau und fertig ausgegeben.
Sobald ein Treffer bei einer Verzweigung gemacht wurde, werden neben den Anweisungen in der Verzweigung auch alle darauffolgenden Anweisungen der anderen Verzweigungen ausgeführt! Hört sich nicht ganz logisch an, aber so ist das nun mal.
Um nur die Anweisungen der jeweiligen Verzweigung auszuführen, nutzen wir das Schlüsselwort break.
Nachdem break aufgerufen wurde, wird jede Anweisung in dem switch-Block ignoriert und das Programm läuft nach dem switch-Block weiter.

Das switch case Konstrukt mit break und default in Java

Die break-Anweisung kannst du übrigens neben den Switch Blöcken auch in Java Schleifen wiederfinden.
Mit dem neu gesammelten Wissen müsste also das vorherige Beispiel so aussehen:

class SwitchBeispiel {

  enum Farben {rot, gelb, blau}

  public static void main(String [] args) { 
    
    Farben c = Farben.gelb;
    
    switch(c) {
      case rot:
        System.out.print("rot ");
        break;
      case gelb:
        System.out.print("gelb ");
        break;
      case blau:
        System.out.print("blau ");
        break;
      default:
        System.out.println("fertig");
    }
  }
}

Wie du sehen kannst, fehlt eine break-Anweisung bei der default Verzweigung.
Das liegt daran, dass die default-Verzweigung die letzte ist und nach dieser keine weiteren Verzweigungen und somit keine Anweisungen folgen können.

2.1. Mach dir die Switch Case Java Logik zunutze!

Auch wenn dir das Durchlaufverhalten des Java Swtichs am Anfang komisch vorkommt, hat es dennoch einige Vorteile, die du dir zu Nutze machen kannst!
Du könntest beispielsweise so mehrere Bedingungen gleichzeitig abfangen und den gleichen Inhalt dir wiedergeben lassen. Hier mal ein Beispiel:

switch(i) {
  case 0:
    System.out.print("null");
    break;
  case 1:
  case 2:
  case 3:
  case 4:
  case 5:
    System.out.print("1 bis 5");
    break;
  case 6:
    System.out.print("6");
    break;
  default:
    System.out.print("default");
}

So würde im Falle das i = 1, 2, 3, 4, oder 5 ist dasselbe Ergebnis ausgegeben werden.

3. Die Standardverzweigung: default

Du hast vielleicht schon bemerkt das wir zu jedem switch-Block auch die Standardverzweigung default am Ende hinzufügen. Diese Verzweigung ist optional und es ist vollkommen dir überlassen ob du diese für dein Programm nutzen willst.
Es empfiehlt sich aber diese zu nutzen, um mögliche Fehler zu reduzieren und Fälle abzufangen wo keine Bedingung zutrifft.
Im Grunde genommen kannst du dir die default-Verzweigung wie das else-Statement in einer if-else-Bedingung vorstellen.

4. switch case vs. if-else

Wenn es um Verzweigungen geht, hört sich die if-else-Bedingung nach der besten Lösung an. Es wird aber ziemlich umständlich, wenn wir mit mehreren Pfaden arbeiten müssen. Betrachten wir mal folgendes Beispiel:

import static java.lang.System.out;
import java.util.*;

class TagDerWoche {
  public static void main(String[] args) {

    Calendar c = Calendar.getInstance();
    Date d = new Date();
    c.setTime(d);
    int tagDerWoche = c.get(Calendar.DAY_OF_WEEK);

    if      (tagDerWoche == 1) { out.println("Sonntag");}
    else if (tagDerWoche == 2) { out.println("Montag");}
    else if (tagDerWoche == 3) { out.println("Dienstag"); }
    else if (tagDerWoche == 4) { out.println("Mittwoch"); }
    else if (tagDerWoche == 5) { out.println("Donnerstag"); }
    else if (tagDerWoche == 6) { out.println("Freitag"); }
    else if (tagDerWoche == 7) { out.println("Samstag"); }
    else { out.println("Unbekannt"); } // Dieser Fall wird nie eintreten
  }
}

In den ersten paar Zeilen erstellen wir ein Calendar Objekt, erhalten den aktuellen Tag und dann den Tag der Woche, den wir als int geliefert bekommen. Das Ganze sieht auf den ersten Blick nicht so schlimm aus, aber auch nur weil wir eine Anweisung pro Verzweigung ausführen und der Code auf Leserlichkeit optimiert wurde.

In diesem Falle wäre ein switch-Block die bessere Lösung. Lass uns mal schauen wie das Beispiel in einem switch-Block aussehen könnte.

import static java.lang.System.out;
import java.util.Calendar;
import java.util.Date;

class TagDerWoche {
  public static void main(String[] args) {

    Calendar c = Calendar.getInstance();
    Date d = new Date();
    c.setTime(d);
    int tagDerWoche = c.get(Calendar.DAY_OF_WEEK);
    String tag = "";

    switch(tagDerWoche) {
      case 1:
        tag = "Sonntag";
        break;
      case 2:
        tag = "Montag";
        break;
      case 3:
        tag = "Dienstag";
        break;
      case 4:
        tag = "Mittwoch";
        break;
      case 5:
        tag = "Donnerstag";
        break;
      case 6:
        tag = "Freitag";
        break;
      case 7:
        tag = "Samstag";
        break;
      default:
        tag = "Keine Ahnung";
    }
    out.printf("Heute ist %s", tag);
  }
  // Wenn break aufgerufen wird, landen wir hier.
}

Es ist zwar länger, aber dafür weitaus einfacher zu lesen und nachhaltig zu pflegen.

5. Verschachtelte switch-case Konstrukte

Das switch case Java Konstrukt kann, genau wie eine if-else-Bedingung, verschachtelt sein. Sehen wir uns das mal an einem Beispiel an:

String Branch = "aa";
int num = 3;

switch (num) {
  case 1:
    System.out.println("Fall 1");
    break;
  case 2:
    switch (Branch) // Verschachteltes switch
    {
      case "aa":
      case "ab":
        System.out.println("");
        break;

      case "bb":
        System.out.println("bb");
        break;

      default:
        System.out.println("unbekannt");
    }
}

Dabei gibt es keine Grenze wie tief man verschachteln kann, jedoch ist es zu empfehlen die Verschachtelung nicht zu tief zu machen, da der Code schnell unleserlich und schwer zu pflegen wird.

6. Zusammenfassung: Das Switch Case Java Konstrukt

  • Switch Konstrukte können einfacher zu lesen und zu bedienen sein als if-else-Bedingungen, wenn wir mit vielen Verzweigungen arbeiten
  • Pass auf welche Datentypen du in deinem switch-Block nutzt: double, float, long und boolean sind nicht zulässig!
  • Achte darauf das Schlüsselwort break zu nutzen, um den weiteren Verlauf des Konstrukts zu beenden
  • Die default-Verzweigung ist zwar optional, dennoch empfiehlt es sich diese zu nutzen, um sowohl Fehler als auch Ausnahmen besser handzuhaben
  • Du kannst beliebig viele case-Verzweigungen in einem switch-Konstrukt einbauen
  • Wir können verschachtelte switch-Konstrukte mit beliebiger Tiefe bauen, jedoch musst du aufpassen das alles leserlich und leicht zu pflegen bleibt!

Wenn du noch Fragen, Anmerkungen, Kritik oder Lob hast, schreib es bitte in die Kommentare!



Bislang gibt es keine Kommentare. Markier dein Revier und sei der Erste!

Schreibe einen Kommentar

Das könnte dich auch interessieren