Bedingte Anweisungen und optionale Operationen
Unsere Programme waren bisher linear. Mit anderen Worten, die Programme wurden von oben nach unten ohne größere Überraschungen oder bedingtes Verhalten ausgeführt. In der Regel möchten Sie jedoch bedingte Logik zu Ihren Programmen hinzufügen. Damit meinen wir Funktionalität, die in irgendeiner Weise vom Zustand der Variablen des Programms abhängt.
Um den Ablauf eines Programms basierend auf Benutzereingaben zu verzweigen, müssen Sie etwas verwenden, das als bedingte Anweisung bekannt ist. Die einfachste bedingte Anweisung sieht folgendermaßen aus:
System.out.println("Hello, World!");
if (true) {
System.out.println("This code is inevitable!");
}
Hello, World! This code is inevitable!
Eine bedingte Anweisung beginnt mit dem Schlüsselwort if
, gefolgt von Klammern. In die Klammern wird ein Ausdruck gesetzt, der ausgewertet wird, wenn die bedingte Anweisung erreicht wird. Das Ergebnis der Auswertung ist ein boolescher Wert. Oben fand keine Auswertung statt. Stattdessen wurde ein boolescher Wert explizit in der bedingten Anweisung verwendet.
Den Klammern folgt ein Block, der innerhalb der geschweiften Klammern {
und }
definiert ist. Der Quellcode innerhalb des Blocks wird ausgeführt, wenn der Ausdruck innerhalb der Klammern als wahr bewertet wird.
Schauen wir uns ein Beispiel an, bei dem wir Zahlen in der bedingten Anweisung vergleichen.
int number = 11;
if (number > 10) {
System.out.println("The number was greater than 10");
}
Wenn der Ausdruck in der bedingten Anweisung als wahr bewertet wird, geht die Ausführung des Programms zu dem Block über, der von der bedingten Anweisung definiert wird. Im obigen Beispiel lautet die Bedingung "wenn die Zahl in der Variable größer als 10 ist". Andernfalls, wenn der Ausdruck als falsch bewertet wird, geht die Ausführung zur Anweisung nach der schließenden geschweiften Klammer der aktuellen bedingten Anweisung über.
NB! Eine if
-Anweisung wird nicht durch ein Semikolon abgeschlossen, da die Anweisung nach der Bedingung nicht endet.
Code-Einrückung und Blockanweisungen
Ein Codeblock bezieht sich auf einen Abschnitt, der von einem Paar geschweifter Klammern umschlossen ist. Die Quelldatei, die das Programm enthält, enthält den String public class
, gefolgt vom Namen des Programms und der öffnenden geschweiften Klammer des Blocks. Der Block endet mit einer schließenden geschweiften Klammer. Im Bild unten ist der Programmblock hervorgehoben.
Das wiederkehrende Snippet public static void main(String[] args)
in den Programmen beginnt einen Block, und der Quellcode darin wird ausgeführt, wenn das Programm gestartet wird - dieses Snippet ist tatsächlich der Ausgangspunkt aller Programme. Wir haben tatsächlich zwei Blöcke im obigen Beispiel, wie auf dem Bild unten zu sehen ist.
Blöcke definieren die Struktur und die Grenzen eines Programms. Eine geschweifte Klammer muss immer ein passendes Paar haben: Jeder Code, dem eine schließende (oder öffnende) geschweifte Klammer fehlt, ist fehlerhaft.
Eine bedingte Anweisung markiert auch den Beginn eines neuen Codeblocks.
Neben der Definition der Programmstruktur und -funktionalität haben Blockanweisungen auch Einfluss auf die Lesbarkeit eines Programms. Code, der sich innerhalb eines Blocks befindet, ist eingerückt. Beispielsweise ist jeder Quellcode innerhalb des Blocks einer bedingten Anweisung vier Leerzeichen tiefer eingerückt als der if
-Befehl, der die bedingte Anweisung gestartet hat.Sie können auch durch Drücken der Tabulatortaste (die Taste links neben 'q') Ihren Code einrücken. Wenn der Block endet, d. h. wenn Sie auf ein }
-Zeichen stoßen, endet auch die Einrückung. Das }
-Zeichen befindet sich auf derselben Einrückungsebene wie der if
-Befehl, der die bedingte Anweisung gestartet hat.
Das folgende Beispiel ist falsch eingerückt.
if (number > 10) {
number = 9;
}
Das folgende Beispiel ist korrekt eingerückt.
if (number > 10) {
number = 9;
}
In Java sind "Fehler", die durch falsches Einrücken, oder durch die evtl. Vermischung von Einrücken mit Tabulator und Einrücken mit Leerzeichen keine syntaktischen Fehler, sondern machen "nur" Ihren Code unleserlich. Andere Programmiersprachen (wie z.B. Python) sind da viel strikter. IDEs wie auch IntelliJ IDEA erlauben die Re-Formatierung Ihres Java-Codes - nutzen Sie diese Möglichkeit um Ihren Code leserlich zu halten:
Vergleichsoperatoren
>
größer als>=
größer als oder gleich<
kleiner als<=
kleiner als oder gleich==
gleich!=
ungleich
int number = 55;
if (number != 0) {
System.out.println("The number is not 0");
}
if (number >= 1000) {
System.out.println("The number is at least 1000");
}
The number was not 0
else
Wenn der Ausdruck innerhalb der Klammern der bedingten Anweisung als falsch bewertet wird, geht die Ausführung des Codes zur Anweisung nach der schließenden geschweiften Klammer der aktuellen bedingten Anweisung über. Dies ist nicht immer erwünscht, und in der Regel möchten Sie eine alternative Option erstellen, wenn der bedingte Ausdruck als falsch bewertet wird.
Dies kann mit Hilfe des else
-Befehls erfolgen, der zusammen mit dem if
-Befehl verwendet wird.
int number = 4;
if (number > 5) {
System.out.println("Your number is greater than five!");
} else {
System.out.println("Your number is five or less!");
}
Your number is five or less!
Wenn für eine bedingte Anweisung ein else
-Zweig angegeben wurde, wird der von dem else-Zweig definierte Block ausgeführt, wenn die Bedingung der bedingten Anweisung falsch ist. Der else
-Befehl befindet sich in derselben Zeile wie die schließende Klammer des Blocks, der vom if
-Befehl definiert wird.
Weitere Bedingungen: else if
Im Falle mehrerer Bedingungen verwenden wir den else if
-Befehl. Der Befehl else if
ist wie else
, aber mit einer zusätzlichen Bedingung. else if
folgt der if
-Bedingung, und es kann mehrere geben.
int number = 3;
if (number == 1) {
System.out.println("The number is one");
} else if (number == 2) {
System.out.println("The number is two");
} else if (number == 3) {
System.out.println("The number must be three!");
} else {
System.out.println("Something else!");
}
The number must be three!
Lesen wir das obige Beispiel: 'Wenn die Zahl eins ist, dann drucke "The number is one", sonst, wenn die Zahl zwei ist, dann drucke "The number is two", sonst, wenn die Zahl drei ist, dann drucke "The number must be three!". Andernfalls drucke "Something else!"'
Die schrittweise Visualisierung des obigen Codes:
Ausführungsreihenfolge von Vergleichen
Die Vergleiche werden von oben nach unten ausgeführt. Wenn die Ausführung eine bedingte Anweisung erreicht, deren Bedingung wahr ist, wird deren Block ausgeführt und die Vergleiche stoppen.
int number = 5;
if (number == 0) {
System.out.println("The number is zero.");
} else if (number > 0) {
System.out.println("The number is greater than zero.");
} else if (number > 2) {
System.out.println("The number is greater than two.");
} else {
System.out.println("The number is less than zero.");
}
The number is greater than zero.
Das obige Beispiel druckt den String "The number is greater than zero.", auch wenn die Bedingung number > 2
wahr ist. Der Vergleich stoppt bei der ersten Bedingung, die als wahr bewertet wird.
Bedingte Anweisungsausdrücke und die boolesche Variable
Der Wert, der zwischen die Klammern der bedingten Anweisung gesetzt wird, sollte nach der Auswertung vom Typ boolean sein. boolean
-Variablen sind entweder true oder false.
boolean isTrue = true;
System.out.println("The value of the boolean variable is " + isTrue);
The value of the boolean variable is true
Die bedingte Anweisung kann auch wie folgt erstellt werden:
boolean isTrue = true;
if (isTrue) {
System.out.println("Pretty wild!");
}
Pretty wild!
Vergleichsoperatoren können auch außerhalb von Bedingungen verwendet werden. In diesen Fällen wird der boolesche Wert, der aus dem Vergleich resultiert, in einer booleschen Variable für die spätere Verwendung gespeichert.
int first = 1;
int second = 3;
boolean isGreater = first > second;
Im obigen Beispiel enthält die boolesche Variable isGreater
jetzt den booleschen Wert false. Wir können das vorherige Beispiel erweitern, indem wir eine bedingte Anweisung hinzufügen.
int first = 1;
int second = 3;
boolean isItLessThan = first < second;
if (isItLessThan) {
System.out.println("1 is smaller than 3!");
}
Der Code im obigen Bild wurde bis zu dem Punkt ausgeführt, an dem die Variablen des Programms erstellt und ihnen Werte zugewiesen wurden. Die Variable isItLessThan
hat den Wert true
. Als nächstes in der Ausführung steht der Vergleich if (isItLessThan)
- der Wert für die Variable isItLessThan
wird in ihrem Container gefunden, und das Programm druckt schließlich:
1 is smaller than 3!
Bedingte Anweisungen und das Vergleichen von Zeichenketten
Auch wenn wir ganze Zahlen, Gleitkommazahlen und boolesche Werte mit zwei Gleichheitszeichen (variable1 == variable2
) vergleichen können, können wir die Gleichheit von Zeichenketten nicht mit zwei Gleichheitszeichen vergleichen.
Sie können dies mit dem folgenden Programm ausprobieren:
Scanner reader = new Scanner(System.in);
System.out.println("Give the first string:");
String first = reader.nextLine();
System.out.println("Give the second string:");
String second = reader.nextLine();
if (first == second) {
System.out.println("The strings were the same!");
} else {
System.out.println("The strings were different!");
}
Give the first string: same Give the second string: same The strings were different!
Give the first string: same Give the second string: different The strings were different!
Dies hat mit dem internen Aufbau von Zeichenketten und der Implementierung des Variablenvergleichs in Java zu tun, wir werden das später in der Vorlesung detailliert analysieren. Hier eine vereinfachte Erklärung, die ohne Begirffe wie primitive Datentypen und Referenztypen auskommt: Zeichenketten können eine potentiell unbegrenzte Anzahl von Zeichen enthalten, während ganze Zahlen, Gleitkommazahlen und boolesche Werte immer nur eine einzelne Zahl oder einen Wert enthalten. Variablen, die immer nur eine Zahl oder einen Wert enthalten, können mit einem Gleichheitszeichen verglichen werden, während dies bei Variablen, die mehr Informationen enthalten, nicht funktioniert. Wie gesagt, wir werden später in diesem Kurs auf dieses Thema zurückkommen.
Beim Vergleichen von Zeichenketten verwenden wir den equals
-Befehl, der mit Zeichenkettenvariablen verbunden ist. Der Befehl funktioniert folgendermaßen:
Scanner reader = new Scanner(System.in);
System.out.println("Give a string:");
String input = reader.nextLine();
if (input.equals("a string")) {
System.out.println("Great! You followed the instructions correctly.");
} else {
System.out.println("Missed the mark!");
}
Give a string: ok! Missed the mark!
Give a string: a string Great! You followed the instructions correctly.
Der equals-Befehl wird nach einer Zeichenkette geschrieben, indem er mit einem Punkt an die zu vergleichende Zeichenkette angehängt wird. Der Befehl erhält einen Parameter, der die Zeichenkette ist, mit der die Variable verglichen wird. Wenn die Zeichenkettenvariable direkt mit einer Zeichenkette verglichen wird, kann die Zeichenkette in Anführungszeichen in die Klammern des equals-Befehls gesetzt werden. Andernfalls wird der Name der Zeichenkettenvariable, die die zu vergleichende Zeichenkette enthält, in die Klammern gesetzt.
Im folgenden Beispiel wird der Benutzer nach zwei Zeichenketten gefragt. Zuerst überprüfen wir, ob die bereitgestellten Zeichenketten gleich sind, und dann überprüfen wir, ob der Wert einer der beiden Zeichenketten "two strings" ist.
Scanner reader = new Scanner(System.in);
System.out.println("Give two strings:");
String first = reader.nextLine();
String second = reader.nextLine();
if (first.equals(second)) {
System.out.println("The strings were the same!");
} else {
System.out.println("The strings were different!");
}
if (first.equals("two strings")) {
System.out.println("Clever!");
}
if (second.equals("two strings")) {
System.out.println("Smart!");
}
Give two strings: hello world The strings were different!
Give two strings: two strings world The strings were different! Clever!
Give two strings: same same The strings were the same!
Logische Operatoren
Der Ausdruck einer bedingten Anweisung kann aus mehreren Teilen bestehen, in denen die logischen Operatoren und &&
, oder ||
und nicht !
verwendet werden.
-
Ein Ausdruck, der aus zwei Ausdrücken besteht, die mit dem und-Operator verbunden sind, ist wahr, wenn und nur wenn beide verbundenen Ausdrücke als wahr bewertet werden.
-
Ein Ausdruck, der aus zwei Ausdrücken besteht, die mit dem oder-Operator verbunden sind, ist wahr, wenn einer oder beide der verbundenen Ausdrücke als wahr bewertet werden.
-
Logische Operatoren werden nicht verwendet, um den booleschen Wert von wahr zu falsch oder von falsch zu wahr zu ändern.
Im nächsten Beispiel kombinieren wir zwei einzelne Bedingungen mit &&
, also dem und-Operator. Der Code wird verwendet, um zu überprüfen, ob die Zahl in der Variablen größer oder gleich 5 und kleiner oder gleich 10 ist. Mit anderen Worten, ob sie im Bereich von 5-10 liegt:
System.out.println("Is the number in the range 5-10: ");
int number = 7;
if (number >= 5 && number <= 10) {
System.out.println("Yes! :)");
} else {
System.out.println("No :(");
}
Is the number in the range 5-10: Yes! :)
Im nächsten Beispiel geben wir zwei Bedingungen mit ||
, also dem oder-Operator: Ist die Zahl kleiner als null oder größer als 100. Die Bedingung ist erfüllt, wenn die Zahl eine der beiden Bedingungen erfüllt:
System.out.println("Is the number smaller than 0 or greater than 100");
int number = 145;
if (number < 0 || number > 100) {
System.out.println("Yes! :)");
} else {
System.out.println("No :(");
}
Is the number smaller than 0 or greater than 100 Yes! :)
In diesem Beispiel kehren wir das Ergebnis des Ausdrucks number > 4
mit !
, also dem nicht-Operator, um. Der nicht-Operator wird so geschrieben, dass der umzukehrende Ausdruck in Klammern gesetzt wird und der nicht-Operator vor die Klammern gesetzt wird.
int number = 7;
if (!(number > 4)) {
System.out.println("The number is not greater than 4.");
} else {
System.out.println("The number is greater than 4.");
}
The number is greater than 4.
Im Folgenden ist eine Tabelle dargestellt, die die Funktionsweise von Ausdrücken mit logischen Operatoren zeigt.
number | number > 0 | number < 10 | number > 0 && number < 10 | !(number > 0 && number < 10) | number > 0 || number < 10 |
---|---|---|---|---|---|
-1 | false | true | false | true | true |
0 | false | true | false | true | true |
1 | true | true | true | false | true |
9 | true | true | true | false | true |
10 | true | false | false | true | true |
Ausführungsreihenfolge von bedingten Anweisungen
Lassen Sie uns mit einem klassischen Programmierbeispiel die Ausführungsreihenfolge von bedingten Anweisungen kennenlernen.
'Schreiben Sie ein Programm, das den Benutzer nach einer Zahl zwischen eins und hundert fragt und diese Zahl ausgibt. Wenn die Zahl durch drei teilbar ist, drucken Sie "Fizz" anstelle der Zahl. Wenn die Zahl durch fünf teilbar ist, drucken Sie "Buzz" anstelle der Zahl. Wenn die Zahl sowohl durch drei als auch durch fünf teilbar ist, drucken Sie "FizzBuzz" anstelle der Zahl.'
Der Programmierer beginnt mit der Lösung der Übung, indem er die Übungsbeschreibung liest und Code entsprechend der Beschreibung schreibt. Die Bedingungen für die Ausführung werden in einer bestimmten Reihenfolge von der Beschreibung präsentiert, und die anfängliche Struktur des Programms wird auf dieser Reihenfolge basieren. Die Struktur wird basierend auf den folgenden Schritten gebildet:
-
Schreiben Sie ein Programm, das den Benutzer nach einer Zahl fragt und diese Zahl ausgibt.
-
Wenn die Zahl durch drei teilbar ist, drucken Sie "Fizz" anstelle der Zahl.
-
Wenn die Zahl durch fünf teilbar ist, drucken Sie "Buzz" anstelle der Zahl.
-
Wenn die Zahl sowohl durch drei als auch durch fünf teilbar ist, drucken Sie "FizzBuzz" anstelle der Zahl.
Wenn-Bedingungen sind leicht mit if - else if - else
-bedingten Anweisungen zu implementieren. Der untenstehende Code wurde basierend auf den oben genannten Schritten geschrieben, funktioniert jedoch nicht korrekt, wie aus dem Beispiel ersichtlich ist.
Scanner reader = new Scanner(System.in);
int number = Integer.valueOf(reader.nextLine());
if (number % 3 == 0) {
System.out.println("Fizz");
} else if (number % 5 == 0) {
System.out.println("Buzz");
} else if (number % 3 == 0 && number % 5 == 0) {
System.out.println("FizzBuzz");
} else {
System.out.println(number);
}
3 Fizz
4 4
5 Buzz
15 Fizz
Das Problem beim vorherigen Ansatz ist, dass die Analyse der bedingten Anweisungen bei der ersten Bedingung, die als wahr bewertet wird, gestoppt wird. Zum Beispiel wird bei dem Wert 15 der String "Fizz" ausgegeben, da die Zahl durch drei teilbar ist (15 % 3 == 0).
Ein Ansatz zur Verbesserung dieses Gedankengangs besteht darin, zuerst die anspruchsvollste Bedingung zu finden und sie umzusetzen. Danach würden wir die anderen Bedingungen umsetzen. Im obigen Beispiel erfordert die Bedingung "wenn die Zahl sowohl durch drei als auch durch fünf teilbar ist" das Eintreten von zwei Fällen. Jetzt wäre der Gedankengang folgendermaßen:
-
Schreiben Sie ein Programm, das Benutzereingaben liest.
-
Wenn die Zahl sowohl durch drei als auch durch fünf teilbar ist, drucken Sie "FizzBuzz" anstelle der Zahl.
-
Wenn die Zahl durch drei teilbar ist, drucken Sie "Fizz" anstelle der Zahl.
-
Wenn die Zahl durch fünf teilbar ist, drucken Sie "Buzz" anstelle der Zahl.
-
Andernfalls druckt das Programm die vom Benutzer eingegebene Zahl.
Jetzt scheint das Problem gelöst zu sein.
Scanner reader = new Scanner(System.in);
int number = Integer.valueOf(reader.nextLine());
if (number % 3 == 0 && number % 5 == 0) {
System.out.println("FizzBuzz");
} else if (number % 3 == 0) {
System.out.println("Fizz");
} else if (number % 5 == 0) {
System.out.println("Buzz");
} else {
System.out.println(number);
}
2 2
5 Buzz
30 FizzBuzz