If-Else, Boolsche Ausdrücke, Wahrheitstabellen

1. Das if bzw. if – else Statement

1.1. Idee

Um ein Programm "intelligent" zu machen, benötigen wir zwingend ein Konzept, nicht nur sequenziell eine Anweisung nach der anderen abzuarbeiten. Es soll in Abhängigkeit von Bedingungen, die entweder zutreffen oder nicht zutreffen (also logische Aussagen bilden, die wahr oder falsch sein können) unterschiedliche Anweisungen ausgeführt werden.

Dazu wird das so schön kompakte englische Wort if (wenn) genutzt – und bei Bedarf zusätzlich sein Gegenstück else (hier als anderenfalls zu übersetzen).

Als Bedingung wird ein Wahrheitswert / boolscher Wert (true/false) genutzt, der entweder direkt verwendet oder durch Auswertung eines Ausdrucks gebildet wird.

1.2. Basis-Beispiel

Hier ein minimalistisches Beispiel:

if (true) {
    System.out.println("ich bin sichtbar, weil's wahr ist");
    // beliebige Folge weiterer Anweisungen
}

Das hat erst dann leicht erkennbaren Sinn, wenn nicht das boolean-Literal direkt hier steht, sondern eine boolean Variable, die auch false enthalten könnte:

boolean doIt = true;  // oder false
if (doIt) {
    System.out.println("ich bin sichtbar, weil's wahr ist");
    // beliebige Folge weiterer Anweisungen
}

Noch praktischer sieht es aus, wenn ein boolscher Ausdruck verwendet wird, der nach Auswertung true oder false ergibt:

int wert = 5;
if (wert > 2) {
    System.out.println("ich bin sichtbar, weil 5 größer als 2 ist");
    // beliebige Folge weiterer Anweisungen
}

1.3. Erweiterung um "anderenfalls"

Oft möchte man nicht nur bei Zutreffen einer Bedingung reagieren, sondern auch bei Nicht-Zutreffen eine (andere) Reaktion setzen.

Dazu wird das Schlüsselwort else eingeführt – hier als "anderenfalls" zu verstehen:

boolean doIt = false;  // oder true
if (doIt) {
    System.out.println("ich bin sichtbar, weil's wahr ist");
} else {   // falls 'doIt' auf 'false' gesetzt war:
    System.out.println("ich zeige das Nicht-Zutreffen an");
}

1.4. Erweiterung um Mehrfach-Verzweigung

Nun erweitern wir nochmals, um auch mehrere Bedingungen/Alternativen abzudecken:

public void printWasserTemperaturBereich(int temp) {
    System.out.print("Wasserzustand ist: ");
    if (temp < -273) {
        System.out.println("unmoeglich");
    } else if (temp < 0) {
        System.out.println("Eis");
    } else if (temp == 0) {
        System.out.println("frierend");
    } else if (temp < 15) {
        System.out.println("kalt");
    } else if (temp < 38) {
        System.out.println("warm");
    } else if (temp < 100) {
        System.out.println("heiss");
    } else {
        System.out.println("Dampf");
    }
    System.out.println("Fertig!");
}

Hier wird der erste "if"- oder "else-if"-Zweig, der zutrifft, "betreten" und ausgeführt, danach wird HINTER das Ende aller Verzweigungen gesprungen (Ausgabe von "Fertig!").
Es wird also MAXIMAL EIN "Zweig" ausgeführt.
Wenn ein abschließender "else"-Zweig existiert, wird dieser ausgeführt, falls bis dahin kein anderer Zweig betreten wurde.
Das abschließende "else" stellt also sicher, dass in jedem Falle GENAU EIN Zweig ausgeführt wird.

Die Bedingungen müssen übrigens in keiner Weise logisch zusammenhängen – sie werden einfach der Reihe nach "probiert", bis die erste zutrifft.

2. Bedingungs-Ausdrücke (Conditional Expressions)

Die Bedingung, die als "Schalter" im "if" verwendet wird, muss also – wie oben gezeigt – einen boolean Wert liefern. Eine solche Bedingung kann als Bedingungsausdruck (conditional expression, boolscher Ausdruck) beliebig komplex sein.
Sie kann sich zusammensetzen aus:

  • value true, false

  • boolean Variablen

  • Vergleichsausdrücken wie obiges wert > 2

  • Methodenaufrufen mit Rückgabetyp boolean

  • logischen ODER: '||' bzw. UND: '&&'

  • sowie Negationen: '!' wie !(wert > 2) (gleichbedeutend mit wert <= 2)

  • sowie aus Kombinationen daraus

  • optional mit runden Klammern gruppiert, um die Auswertungs-Reihenfolge zu steuern, Negationen auf größere Bereiche wirken zu lassen, etc.

public class BoolExprDemo {

    public boolean gt5(int value) {
        return value > 5;  // liefert true, wenn value größer als 5, sonst false
    }

    public void demo1(int value) {
        boolean result = value > 9 && value < 100;
        System.out.println("Ergebnis für value=" + value + " von '"
                + "value > 9 && value < 100' (2-stellige Z.) ist: " + result);
    }

    public void demo2(boolean onOff, int value) {
        boolean result = false || onOff && (!gt5(value) || value < -999);
        System.out.println("Ergebnis für onOff=" + onOff + ", value=" + value + "\n  von '"
                + "false || onOff && (!gt5(value) || value < -999)"
                + "' ist: " + result);
    }
}

3. Wahrheitstabellen

TODO: Konzept Wahrheitstafeln erläutern, Beispiele

Die Aussagenlogik ist die älteste (schon im antiken entwickelt) und einfachste Art der Logik. Es werden nur Aussagen/Behauptungen/Aussagenvariable betrachtet, die entweder zutreffen oder nicht (true / false, ja / nein, 0 / 1).

Es stellt sich auch heraus, dass bei Zuordnung 0 → false und 1 → true logische und algebraische Operationen eng zusammenrücken – Mathematische Operationen lassen sich mit wenigen Zusatzkonzepten durch logische Operationen umsetzen!

Eine Aussage wird dabei als Behauptung, die wahr oder falsch sein kann, betrachtet. Im Alltag stößt man auf Schritt und Tritt an die Grenzen dieses Ansatzes, in formal spezifizierten Systemen (z.B. Computerprogramme) ist er allerdings sehr gut verwendbar.

Hat man z.B. eine Zahlen-Variable x, hat die Aussage x < 7 (Obergrenze) eine sehr klare Antwort (abhängig vom gerade enthaltenen Wert.) – diese ist entweder true oder false. Bei Wert 5 stünde dan faktisch 5 < 7 mit Antwort true.

Abhängig vom Wahrheitswert (nur true und false möglich) sind vermutlich unterschiedliche Aktivitäten zu setzen.

Wenn man nun auch eine Untergrenze prüfen will, indem man schreibt x > 2, dann ist für obigen Wert 5 auch hier die Antwort true.

Da beide Antworten true sind, ist die Gesamtantwort der Aussage x > 2 AND x < 7 ebenfalls true. In allen anderen 3 möglichen Kombinationen von true und false ist das Gesamtergebnis der UND-Verknüpfung false.

Die einfachste logische Operation (neben der trivialen Identitäts-Operation) ist die Negation eines Wahrheitswertes: false → true und true → false.
Sie hat offenbar nur einen Operanden. (Die Identitätsoperation und die Negation sind die beiden einzigen "bijektiven"= "umkehrbar eindeutigen" Operationen.)

4. Gültigkeits-Prüfung von Methodenparametern

Die oben besprochenen Verzweigungsmöglichkeiten nutzt man unter anderem, um Übergabeparameter von Methoden auf Gültigkeit zu prüfen.

Bei ungültigen Werten wird eine aussagekräftige Fehlermeldung ausgegeben und möglichst sinnvoll auf den ungültigen Wert reagiert.

Wenn alles passt, wird der geplante Ablauf durchgeführt.

Vorerst prüfen wir nur Zahlenwerte – Text-Prüfung erfordert noch weiteres Vorwissen.

TODO: fertigstellen