1.04 Kontrollstrukturen Teil 1 – if-Abfragen und for-Schleifen

Verzweigungen / if-Abfragen

Einfache if-Abfragen

Bisher liefen unsere Programme immer stur von oben nach unten ab. Mithilfe von Verzweigungen können wir den Ablauf interessanter gestalten:

public class BedingteAnweisung {

    public static void main(String[] args) {

        int konto;
        konto = 0;
        
        konto = konto + 100;
        konto = konto - 10;
        
        if (konto > 0){
            System.out.println("Noch Guthaben vorhanden.");
        } else{
            System.out.println("Kein Guthaben mehr!");
        }

    }

}

Mit dem Schlüsselwort if wird die Verzweigung eingeleitet. In den runden Klammern danach folgt eine Bedingung. In diesem Fall lautet die Bedingung, dass der Wert der Variablen konto positiv sein soll. In den dann folgenden geschweiften Klammern stehen die Anweisungen die ausgeführt werden sollen, wenn diese Bedingung erfüllt ist – daher spricht man hier auch oft von bedingten Anweisungen.

Danach folgt noch ein else mit weiteren geschweiften Klammern. In diesen Klammern stehen die Anweisungen die ausgeführt werden sollen, wenn die Bedingung nicht erfüllt ist.

Starten wir das Programm, erhalten wir die Ausgabe „Noch Guthaben vorhanden.“. Verändern wir die Zahlenwerte so, dass konto nicht mehr positiv ist, erhalten wir entsprechend die Ausgabe „Kein Guthaben mehr!“.

Den Ablauf unseres Programms können wir auch mithilfe eines Flussdiagramms darstellen:

Ein Flussdiagramm in dem eine Verzweigung dargestellt wird.
Flussdiagramm mit einer Verzweigung. Anklicken zum Vergrößern.

Die Formen, die wir hier verwenden, sind als Standards festgelegt:

  • Ein Oval oder Rechteck mit abgerundeten Ecken steht für Start und Ende.
  • Ein Rechteck steht für eine ganz normale Anweisung.
  • Eine Raute steht für eine Verzweigung oder auch Entscheidung.
  • Ein Parallelogramm steht für eine Ausgabe oder später auch noch für eine Eingabe.

Wenn im Laufe der Zeit unsere Programme komplizierter werden, kann es oft hilfreich sein, sich den Ablauf so vor Augen zu führen.

Sehen wir uns noch ein Beispiel an:

public class BedingteAnweisungen_02 {

    public static void main(String[] args) {

        boolean dieSonneScheint;
        boolean mehrAlsZehnEuro;

        dieSonneScheint = true;
        mehrAlsZehnEuro = true;

        if (dieSonneScheint && mehrAlsZehnEuro){
            System.out.println("Ich gehe ein Eis essen!");
            System.out.println(":)");
        } else{
            System.out.println("Ich gehe kein Eis essen.");
        }

    }

}

Hier lautet die Bedingung dieSonneScheint && mehrAlsZehnEuro. Allgemein kann eine Bedingung irgendein Ausdruck sein, der entweder wahr oder falsch ist. Im ersten Beispiel liefert die Auswertung des Vergleichs konto > 0 als Ergebnis entweder true oder false. In diesem Beispiel liefert die Verknüpfung dieSonneScheint && mehrAlsZehnEuro auch entweder true oder false.

Wir sehen hier auch, dass zwei Anweisungen ausgeführt werden sollen, wenn die Bedingung erfüllt ist. Es dürften natürlich noch beliebig mehr Anweisungen sein.

Manchmal kann es sein, dass bei einer nicht erfüllten Bedingung gar keine Anweisungen ausgeführt werden sollen. In so einem Fall lassen wir den else-Zweig einfach weg:

public class BedingteAnweisungen_03 {

    public static void main(String[] args) {

        boolean dieSonneScheint;
        boolean mehrAlsZehnEuro;

        dieSonneScheint = true;
        mehrAlsZehnEuro = true;

        if (dieSonneScheint && mehrAlsZehnEuro){
            System.out.println("Ich gehe ein Eis essen!");
            System.out.println(":)");
        }

    }

}

Hier ist der Clip zur Einführung von if-Abfragen. Dort werden ähnliche Beispiele verwendet, aber nicht genau dieselben, damit sich ein Ansehen lohnt 😉

Verschachtelte Verzweigungen

Wenn innerhalb einer Verzweigung eine weitere Abfrage eingeleitet wird, sprechen wir von verschachtelten Verzweigungen.

Hier würde ich empfehlen, zunächst den Clip zu sehen, da man dort alles etwas einfacher nachvollziehen kann.

Kommen wir auch hier zu einem Beispiel:

public class BedingteAnweisungen_04 {

    public static void main(String[] args) {

        boolean dieSonneScheint;
        boolean mehrAlsZehnEuro;

        dieSonneScheint = true;
        mehrAlsZehnEuro = false;

        if (dieSonneScheint && mehrAlsZehnEuro){
            System.out.println("Ich gehe ein Eis essen!");
            System.out.println(":)");
        } else{
            System.out.println("Ich gehe kein Eis essen.");

            if (!dieSonneScheint){ // Beachte: Das ! sorgt für eine NEGATION.
                System.out.print("Bei schlechtem Wetter schmeckt es eh nicht.");
            }else{
                System.out.println("Ich muss gerade ein wenig sparen.");
            }

        }

    }

}

Hier untersuchen wir im else-Zweig ein wenig genauer, warum wir kein Eis essen gehen. In diesem Fall muss ja entweder die Sonne nicht scheinen oder wir haben nicht genug Geld dabei oder beides. Wir prüfen also zuerst, ob die Sonne nicht scheint. Ist dies der Fall, wird das Wetter als Grund angegeben, dass wir kein Eis essen. Andernfalls – falls wir also kein Eis essen aber dennoch die Sonne scheint – werden unsere Finanzen als Grund angegeben.

In einem Flussdiagramm können wir den Ablauf wie folgt darstellen, wobei hier das Deklarieren und Initialisieren der Variablen weggelassen wird:

Ein Flussdiagramm mit einer verschachtelten Verzweigung.
Ein Flussdiagramm mit einer verschachtelten Verzweigung. Anklicken zum Vergrößern.

Nun wird es tatsächlich recht kniffelig und wir müssen aufpassen, dass wir uns mit der Logik, die hier hinter steckt nicht vertun. Spielen wir aber die vier verschiedenen Kombinationen von true und false für unsere beiden Bedingungen durch, sehen wir, dass tatsächlich immer die korrekte Ausgabe geliefert wird.

Wenn Du genau hinsiehst, fällt Dir vielleicht auf, dass immer nur ein Grund angegeben wird, warum wir kein Eis essen – auch dann, wenn es zwei Gründe gibt. Wir können unsere Fallunterscheidung also noch weiter auf die Spitze treiben:

Ein Flussdiagramm mit insgesamt drei Verzweigungen.
Ein Flussdiagramm mit insgesamt drei Verzweigungen. Anklicken zum Vergrößern.

Im Diagramm habe ich das Ende einer Abfrage jeweils durch einen kleinen farbigen Punkt markiert, damit wir besser erkennen, wo welche Abfrage beendet wird.

In Java sieht dies dann so aus:

public class BedingteAnweisungen_04 {

    public static void main(String[] args) {

        boolean dieSonneScheint;
        boolean mehrAlsZehnEuro;

        dieSonneScheint = false;
        mehrAlsZehnEuro = true;

        if (dieSonneScheint && mehrAlsZehnEuro){
            System.out.println("Ich gehe ein Eis essen!");
            System.out.println(":)");
        } else{
            
            System.out.println("Ich gehe kein Eis essen.");

            if (!dieSonneScheint){

                if (!mehrAlsZehnEuro){
                    System.out.println("Ich muss gerade ein wenig sparen, aber das Wetter ist ja sowieso schlecht.");
                } else{
                    System.out.println("Bei schlechtem Wetter schmeckt es ja doch nicht.");
                }

            }else{
                System.out.println("Ich muss gerade ein wenig sparen.");
            }

        }

    }
}

else if-Anweisungen

Wenn wir eine ganze Reihe von sich gegenseitig ausschließenden Fällen durchgehen möchten, von denen nur ganze genau einer eintreten kann (und soll), können wir mit tief verschachtelten Verzweigungen arbeiten.

In diesem Beispiel wird zunächst ein Kontostand angegeben. Danach werden verschiedene Fälle überprüft und je nach Kontostand wird eine andere Meldung ausgegeben.

public class BedingteAnweisungenOhneElseIf {

    public static void main(String[] args) {

        int konto;
        konto = 90;

        if (konto > 100){
            System.out.println("Super!");
        } else {
            if(konto > 0){
                System.out.println("OK");
            }else{
                if(konto == 0){
                    System.out.println("Pleite!");
                }else{
                    System.out.println("Schulden!");
                }
            }
        }
    }
}

Wir müssen hier die Verzweigungen verschachteln. Würden wir einfach nacheinander einzelne Verzweigungen starten, würden wir möglicherweise mehrere Meldungen ausgegeben bekommen.

Da solche Konstruktionen häufig anzutreffen sind und unübersichtlich werden können, weil der Programmtext immer weiter nach rechts eingerückt wird, gibt es als Alternative die else-if-Anweisung:

public class BedingteAnweisungenMitElseIf {

    public static void main(String[] args) {

        int konto;
        konto = 90;

        if (konto > 100){
            System.out.println("Super!");
        }else if(konto > 0){
            System.out.println("OK");
        }else if(konto == 0){
            System.out.println("Pleite!");
        }else{
            System.out.println("Schulden!");
        }

    }

}

Dieses Programm leistet genau dasselbe wie das oben. Wir sparen uns hier aber das Einrücken des Textes und eine Menge Klammern.

Hier ist der Clip zu diesem Abschnitt:

Schleifen

Wenn gewisse Arbeitsschritte mehrere Male (vielleicht leicht verändert) durchgeführt werden sollen, dann bietet es sich oft an, mit Schleifen zu arbeiten. Als einfaches Beispiel zum Einstieg wollen wir uns die Zahlen von 0 bis 10 anzeigen lassen:

Darstellung einer Schleife in einem Flussdiagramm.
Darstellung einer Schleife in einem Flussdiagramm. Anklicken zum Vergrößern.

Das Diagramm sieht dem einer Verzweigung zwar ähnlich, enthält aber den wesentlich Unterschied, dass der Pfeil nach dem Erhöhen der Variable wieder zurück nach oben führt.

Es gibt verschiedene Arten von Schleifen, von denen jede ihre Vor- und Nachteile beim Programmieren hat. Minimalisten könnten an dieser Stelle einwenden, dass man durchaus mit einer einzigen Art auskommen könnte. Du wirst aber sehen, dass in manchen Situationen eine Schleifenart einfach intuitiver sein wird als andere.

Einfache Zählscheifen / for-Schleifen

Zählschleifen bieten sich an, wenn Du mithilfe einer Variablen zählen möchtest, wie oft ein Vorgang schon durchgeführt wurde. Unser Beispiel aus dem Diagramm oben passt hier also gut. Dies sieht in Java so aus:

public class Zaehlschleife {
  

  public static void main(String[] args) {

    for (int zaehler = 0; zaehler <= 10; zaehler = zaehler + 1){
      System.out.println(zaehler);
    }

  }
  

}

Wie Du siehst, können wir bei einer Zählschleife drei Angaben machen:

  • Eine Zählvariable und deren Startwert. Hier: int zaehler = 0;
  • Eine Bedingung, in welchem Fall die Schleife weiter durchgeführt werden soll. Hier: zaehler <= 10;
  • Eine Angabe, wie die Zählvariable nach dem Schleifendurchlauf aktualisiert werden soll. Hier: zaehler = zaehler + 1;

Der einzige Befehl, der innerhalb der Schleife ausgeführt werden soll, ist die Ausgabe von zaehler. Du könntest aber in den geschweiften Klammern auch noch mehr Anweisungen machen.

Die Zählvariable wird nach Beenden der Schleife übrigens wieder gelöscht, so dass Du denselben Namen in einer weiteren Schleife verwenden könntest:

public class Zaehlschleife02 {
  

  public static void main(String[] args) {

    for (int zaehler = 0; zaehler <= 10; zaehler = zaehler + 1){
      System.out.println(zaehler);
    }
        
    for (int zaehler = 5; zaehler <= 50; zaehler = zaehler + 5){
      System.out.println(zaehler);
    }
    
    System.out.println(zaehler); // FEHLER!
        
  }
  

}

Die zweite Schleife ist noch vollkommen in Ordnung. Mit dieser kann die Fünferreihe ausgegeben werden. Weil aber die Zählvariable nach Beenden der Schleife nicht mehr existiert, führt die letzte Anweisung zu einem Fehler.

Hier kannst Du Dir den Clip zu diesem Abschnitt ansehen:

Verschachtelte Zählscheifen / for-Schleifen

So wie Du Verzweigungen verschachteln kannst, kannst Du auch Zählschleifen verschachteln. Zum Beispiel so:

Eine verschachtelte Zählschleife. Die innere Schleife ist gelb hervorgehoben.
Eine verschachtelte Zählschleife. Die innere Schleife ist gelb hervorgehoben. Anklicken zum Vergrößern.

Wo vorher noch einzig die Ausgabe der Variable zaehler stand, befindet sich nun noch eine weitere Schleife (gelb hervorgehoben).

In Java kannst Du dies so umsetzen:

public class ZaehlschleifeVerschachtelt {
  

  public static void main(String[] args) {

    for (int zaehler = 0; zaehler <= 9; zaehler = zaehler + 1){
      
      for(int innererZaehler = 0; innererZaehler <= 5; innererZaehler = innererZaehler + 1){
        System.out.print(innerZaehler);		// Ausgabe von innererZaehler
        System.out.print(" ");			// Ausgabe eines Leerzeichens
      }	
      
      System.out.println(); 				// neue Zeile
      
    }
    
        
  }
  

}

Was genau geschieht in diesem Beispiel? Sehen wir uns zuerst die innere Schleife an. Dort werden die Zahlen von 0 bis 5 mit jeweils einem Leerzeichen dazwischen ausgegeben. Ist die innere Schleife beendet, wird in eine neue Zeile gewechselt. Dieser Vorgang wiederholt sich aufgrund der äußeren Schleife zehnmal. Wir erhalten also 10 Zeilen mit den Zahlen von 0 bis 5:

0 1 2 3 4 5 
0 1 2 3 4 5 
0 1 2 3 4 5 
0 1 2 3 4 5 
0 1 2 3 4 5 
0 1 2 3 4 5 
0 1 2 3 4 5 
0 1 2 3 4 5 
0 1 2 3 4 5 
0 1 2 3 4 5

Das Beispiel soll nun so verändert werden, dass wir folgende Ausgabe erhalten:

1 
2 2 
3 3 3 
4 4 4 4 
5 5 5 5 5 
6 6 6 6 6 6 
7 7 7 7 7 7 7 
8 8 8 8 8 8 8 8 
9 9 9 9 9 9 9 9 9

Bevor Du weiter liest, kannst Du selbst versuchen, dies zu erreichen. Das ist eine gute Übung!

Überlegen wir nun gemeinsam, wie wir das Programm anpassen müssen. Zunächst sehen wir, dass in jeder Zeile immer die Zahl ausgegeben wird, die der Zeilennummer entspricht. Vermutlich wird hier System.out.print(zaehler); verwendet, d.h., zaehler wird ausgegeben anstatt innererZaehler. Da die Ausgabe aber mit einer Eins beginnt, muss in der äußeren Schleife der Zähler von 1 bis 9 laufen. Außerdem verändert sich die Anzahl der Ausgaben in jeder Zeile. Die Bedingung in der inneren Schleife kann also nicht mehr innererZaehler <= 5; lauten. Da sich die Anzahl in jeder Zeile verändert, muss hier der Zähler mit im Spiel sein. Konkret so: innererZaehler <= zaehler; Allerdings muss nun auch der innere Zäher bei 1 starten, weil wir sonst zwei Einsen, drei Zweien etc. hätten.

Insgesamt sieht die Anpassung so aus:

public class ZaehlschleifeVerschachtelt {
  

  public static void main(String[] args) {

    for (int zaehler = 1; zaehler <= 9; zaehler = zaehler + 1){
      
      for(int innererZaehler = 1; innererZaehler <= zaehler; innererZaehler = innererZaehler + 1){
        System.out.print(zaehler);		// Ausgabe von innererZaehler
        System.out.print(" ");			// Ausgabe eines Leerzeichens
      }	
      
      System.out.println(); 				// neue Zeile
      
    }
    
        
  }
  

}

Natürlich gibt es auch zu den verschachtelten Zählschleifen einen Clip 😉

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.