252-0027
Einführung in die Programmierung
2.5 “if”-Anweisungen
2.6 Nochmals Schleifen: “while” Loops 2.Y Output
Thomas R. Gross
Department Informatik ETH Zürich
Uebersicht
§ 2.2 Typen und Variable
§ Deklaration von Variablen
§ 2.3 Schleifen (Loops)
§ 2.3.1 “for” Loops
§ 2.3.2 Verschachtelte Schleifen
§ 2.4 Methoden mit Parametern
§ 2.5 “if”-Anweisungen
§ 2.6 Nochmals Schleifen
§ “while” Loops
§ 2.X Input
§ 2.Y Output 2
Faktorisierung für if/else Anweisungen
§ Example:
if (a == 1) {
System.out.println(a);
x = 3;
b = b + x;
} else if (a == 2) {
System.out.println(a);
x = 6;
y = y + 10;
b = b + x;
} else { // a == 3
System.out.println(a);
x = 9;
b = b + x;
}
System.out.println(a);
x = 3 * a;
if (a == 2) { y = y + 10;
}
b = b + x;
Boolesche Ausdrücke
if (((x>0) && (y>0)) && (z > 0)) { // block 1
}
// more code
if (((x>0) && (y>0)) && (z >= 0)) { // block 2
}
§ Was ist an diesem Code Beispiel schlecht?
4
Boolesche Ausdrücke
if (((x>0) && (y>0)) && (z > 0)) { // block 1
}
// more code
if (((x>0) && (y>0)) && (z >= 0)) { // block 2
}
§ Was ist an diesem Code Beispiel schlecht?
§ (x>0) && (y>0) mehrfach berechnet
5
Typ boolean
§ Boolesche Werte können in Variablen des Typs boolean gespeichert werden.
§ boolean ist ein Basistyp (primitive type)
§ Parameterübergabe:
§ Der Typ boolean kennt nur zwei Werte: wahr (true) und falsch (false).
§ boolean quadrant1;
§ Oder boolean quadrant1 = true;
deklarieren boolesche Variable.
Typ boolean
§ Boolesche Werte können in Variablen des Typs boolean gespeichert werden.
§ boolean ist ein Basistyp (primitive type)
§ Parameterübergabe: value semantics
§ Der Typ boolean kennt nur zwei Werte: wahr (true) und falsch (false).
§ boolean quadrant1;
§ Oder boolean quadrant1 = true;
deklarieren boolesche Variable.
Typ boolean
§Ein Vergleich ("test") ist ein boolescher Ausdruck (ein Ausdruck der ein boolean Ergebnis hat).
§ Ergebnis kann in einer Variable des Typs boolean gespeichert werden
§Boolesche Variable können mit den booleschen Operatoren kombiniert werden.
Boolesche Ausdrücke mit boolean Variablen
boolean quadrant1 = (x>0) && (y>0);
if (quadrant1 && (z > 0)) { // block 1
};
// more code
if (quadrant1 && (z >= 0)) { // block 2
}
§ Annahme: keine Aenderung von x, y …. 11
Typ boolean Beispiele
boolean isJugendlicher = (alter < 18);
boolean wohntInZuerich = (plz >= 8000) && (plz < 8100);
// nur fuer volljaehrige aus Zuerich
if (isJugendlicher || !wohntInZuerich) { System.out.println("Kein Zutritt!");
}
Hinweise
§ Manchmal sieht man solchen Code (test ob eine Variable den Wert true hat):
if (isPrime == true) { // schlecht ...
}
§ Das ist nicht nötig und redundant. Besser :
if (isPrime) { // gut ...
}
Hinweise
§ Auch nicht besser ist der Test für false:
if (isPrime == false) { // schlecht
if (!isPrime) { // gut
Bedingte ("short-circuit") Auswertung
§ Für && und || müssen nicht immer beide Operanden ausgewertet werden, um das Ergebnis zu ermitteln
§ Java beendet die Auswertung eines booleschen Ausdrucks sobald das Ergebnis fest steht.
§ Ausdrücke werden von links nach rechts, gemäss Präzedenz ausgewertet
§ && stoppt sobald ein Teil(ausdruck) false ist
§ || stoppt sobald ein Teil(ausdruck) true ist
Bedingte ("short-circuit") Auswertung
§ Java beendet die Auswertung eines booleschen Ausdrucks sobald das Ergebnis fest steht.
§ Ausdrücke werden von links nach rechts, gemäss Präzedenz ausgewertet
§ && stoppt sobald ein Teil(ausdruck) false ist
§ || stoppt sobald ein Teil(ausdruck) true ist
§ Diese Art der Auswertung heisst bedingte Auswertung
§ Folgende Teilausdrücke werden abhängig von zuerst ausgewerteten Ausdrücken (nicht) evaluiert
Auswertung des Tests
§ Wir wollen nur Quotienten (für a,b) grösser als 0 drucken:
Scanner console = new Scanner(System.in);
System.out.print("Eingabe zweier Zahlen: ");
int a = console.nextInt();
int b = console.nextInt();
System.out.println(a + " / " + b + " = " + a/b);
...
Auswertung des Tests
§ Viele "if" Statements machen den Code unlesbar
Scanner console = new Scanner(System.in);
System.out.print("Eingabe zwei Zahlen: ");
int a = console.nextInt();
int b = console.nextInt();
if ( b!=0) {
if ( a/b>0 ) {
System.out.println(a + " / " + b + " = " + a/b);
};
} ...
Auswertung des Tests
§ Wir wollen nur Quotienten (für a,b) grösser als 0 drucken:
Scanner console = new Scanner(System.in);
System.out.print("Eingabe zweier Zahlen: ");
int a = console.nextInt();
int b = console.nextInt();
// a/b > 0 UND // b != 0
System.out.println(a + " / " + b + " = " + a/b);
}
...
Reihenfolge ist wichtig
§ Dieser Code führt zu einer Fehlermeldung wenn b == 0:
// Warning.
Scanner console = new Scanner(System.in);
System.out.print("Eingabe zweier Zahlen: ");
int a = console.nextInt();
int b = console.nextInt();
if (a/b>0) && (b!=0) {
System.out.println(a + " / " + b + " = " + a/b);
};
}
...
Bedingte ("short-circuit") Auswertung
§ Dieser Code führt zu keiner Fehlermeldung wenn b == 0:
// Now there is no problem
Scanner console = new Scanner(System.in);
System.out.print("Eingabe zweier Zahlen: ");
int a = console.nextInt();
int b = console.nextInt();
if (b!=0) && (a/b>0) {
System.out.println(a + " / " + b + " = " + a/b);
};
}
...
38
40
De Morgan's Regeln
De Morgan's Regeln: Regeln für die Negation boolescher Ausdrücke.
§ Praktisch wenn man das Gegenteil eines Ausdrucks braucht.
§ Beispiel:
Ursprünglicher Ausdruck Negierter Ausdruck Alternative
a && b !a || !b !(a && b) a || b !a && !b !(a || b)
Original Negiert
if (x == 7 && y > 3) {
...
}
if (x != 7 || y <= 3) {
...
}
2.5 Nochmals Schleifen
§ Bisher: Obergrenze für Schleifenzähler stand zu Beginn der Schleife fest
§ Jetzt: mehr Flexibilität
§ Korrekte Terminierung wichtig
43
Eine triviale Aufgabe ...
§ Schreiben Sie eine Methode printNumbers die die Zahlen von 1 bis N durch Komma getrennt ausgibt.
Beispiel:
Obergrenze N eingeben: 5
sollte ergeben:
1, 2, 3, 4, 5
Fehlerhafte Lösungen
public static void printNumbers() {
Scanner console = new Scanner(System.in);
System.out.print("Obergrenze N eingeben: ");
int max = console.nextInt();
for (int i = 1; i <= max; i++) { System.out.print(i + ", ");
}
System.out.println(); // to end the line of output }
Output bei Eingabe 5: 1, 2, 3, 4, 5,
Fehlerhafte Lösungen
public static void printNumbers() {
Scanner console = new Scanner(System.in);
System.out.print("Obergrenze N eingeben: ");
int max = console.nextInt();
for (int i = 1; i <= max; i++) { System.out.print(", " + i);
}
System.out.println(); // to end the line of output }
Output bei Eingabe 5: , 1, 2, 3, 4, 5
Gartenzaun Analogie
§ Wir geben n Zahlen aus aber brauchen nur n - 1 Kommas.
§ Aehnlich dem Bau eines Weidezaunes mit Pfosten und Querstreben
§ Wenn wir - wie in der 1. fehlerhaften Lösung – Pfosten und Streben installieren dann hat der letzte Pfosten in der Luft hängende Streben.
for (Laenge des Zauns) { Betoniere Pfosten.
Installiere Querstreben.
}
Schleife
§ Fügen Sie eine Anweisung ausserhalb der Schleife hinzu um den ersten "Pfosten" zu plazieren
Betoniere Pfosten.
for (Laenge des Zauns - 1) { Installiere Querstreben.
Betoniere Pfosten.
}
Lösungen basierend auf dieser Idee
System.out.print(1);
for (int i = 2; i <= max; i++) { System.out.print(", " + i);
}
System.out.println(); // to end the line
Alternative: 1. oder letzter Durchlauf durch die Schleife kann verändert werden:
for (int i = 1; i <= max - 1; i++) { System.out.print(i + ", ");
}
System.out.println(max); // to end the line
"off-by-one" Error
(Um-Eins-daneben-Fehler)§ Die Schleife wurde einmal zuviel (oder einmal zuwenig) durchlaufen.
§ "Zaunpfahlproblem" – es gibt sogar eine D Wikipedia Seite (Inhalt ohne Gewähr)
50
Terminierung von Loops
§ Verwandeln Sie die Methode printNumbers in eine neue Methode printPrimes die alle Primzahlen bis zur
Obergrenze max ausgibt.
§ Beispiel: printPrimes mit Eingabe 50 ergibt:
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47
§ Wenn max < 2, gebe nichts aus.
§ Eine Primzahl p kann in genau zwei Faktoren zerlegt werden: p und 1
53
Beispiellösung
// Prints all prime numbers up to the given max.
public static void main (String[] args) {
Scanner console = new Scanner(System.in);
System.out.print("Input max: ");
int max = console.nextInt();
// Prints all prime numbers up to the given max.
if (max >= 2) {
System.out.print("2");
for (int i = 3; i <= max; i++) {
if (isPrime(i, max)) { // isPrime returns true if i is prime System.out.print(", " + i);
} }
System.out.println();
} }
56
while Schleifen
Klassifizierung von Schleifen
§ bestimmte Schleife (definite loop): Anzahl der Ausführungen des Rumpfes ist vorher bekannt.
§ Die for Schleifen waren bisher immer bestimmte Schleifen.
§ Drucke "hello" 10-mal.
§ Finden Sie alle Primzahlen < einer ganzen Zahl n.
§ Drucken Sie jede ungerade Zahl zwischen 7 und 91.
§ unbestimmte Schleife (indefinite loop): Anzahl der Ausführungen des Rumpfes ist nicht vorher bekannt.
Klassifizierung von Schleifen
§ unbestimmte Schleife (indefinite loop): Anzahl der Ausführungen des Rumpfes ist nicht vorher bekannt.
§ Lesen Sie den Input von der Konsole bis der Benutzer eine nicht- negative ganze Zahl eingibt.
§ Wiederholen Sie bis der Benutzer ein "q" eingegeben hat.
§ Lesen Sie eine Datei bis drei aufeinanderfolgende Sätze mit einem
"!" enden.
§ Nehmen Sie Beiträge (via crowdfunding) entgegen bis das Ziel erreicht ist.
Die while Schleife
§ while Schleife: Führen Sie den Schleifenrumpf so lange aus wie der boolesche Ausdruck test den Wert true ergibt.
while (test) { statement(s);
}
§ Beispiel:
int num = 1; // initialization while (num*num <= 2000) { // test
System.out.print(num + " ");
num = num * 2; // update }
// output: 1 2 4 8 16 32
Die while Schleife
§ while Schleife: Führen Sie den Schleifenrumpf so lange aus wie der boolesche Ausdruck test den Wert true ergibt.
while (test) { statement(s);
}
§ Beispiel:
int num = 1;
while (num*num <= 2000) { System.out.print(num + " ");
num = num * 2;
}
// output: 1 2 4 8 16 32
Anweisung(en) im Loop ausfuehren Ist test wahr?
Anweisung nach Loop ausfuehren
ja nein
62
Beispiellösung
public static boolean isPrime (int arg, int max){
// Determine how many factors the given number has.
boolean found = false;
int step = 2;
while (!found) {
if (arg % step == 0) {
found = true; // another factor found }else { step++ ; // keep on searching } }
// other factor == arg: prime found return (step == arg);
}
Beispiel while Schleife
// finds the first factor of 91, other than 1 int n = 91;
int factor = 2;
while (n % factor != 0) { factor++;
}
System.out.println("First factor is " + factor);
// output: First factor is 7
§ while ist hier bessser als for weil wir nicht wissen wie oft wir den Zähler erhöhen müssen um den 1. Faktor zu finden
§ Hinweiszeichen (Sentinel) ("sentinel"): Ein Wert der das Ende eine Reihe anzeigt
§ sentinel loop: Schleife deren Rumpf ausgeführt wird bis ein Sentinel gesehen wurde
§ Beispiel: Ein Programm soll Zahlen einlesen bis der Benutzer eine 0 eingibt; dann soll die Summe aller eingegebenen Zahlen ausgegeben werden.
§ (In diesem Beispiel ist 0 das Hinweiszeichen/der Sentinel.)
Werte die Hinweise sind …
§ Beispiel: Ein Programm soll Zahlen einlesen bis der Benutzer eine 0 eingibt; dann soll die Summe aller eingegebenen Zahlen ausgegeben werden.
§ (In diesem Beispiel ist 0 das Hinweiszeichen/der Sentinel.) Enter a number (0 to quit): 10
Enter a number (0 to quit): 20 Enter a number (0 to quit): 30 Enter a number (0 to quit): 0 The sum is 60
Werte die Hinweise sind …
Fehlerhafte Lösung
§ Was ist an diesem Programm falsch?
Scanner console = new Scanner(System.in);
int sum = 0;
int number = 1; // "dummy value", anything but 0 while (number != 0) {
System.out.print("Enter a number (0 to quit): ");
number = console.nextInt();
sum = sum + number;
}
System.out.println("The total is " + sum);
Ein anderes Hinweiszeichen …
§ Aendern Sie das Programm so dass -1 der Sentinel ist.
§ Example log of execution:
Enter a number (-1 to quit): 15 Enter a number (-1 to quit): 25 Enter a number (-1 to quit): 10 Enter a number (-1 to quit): 30 Enter a number (-1 to quit): -1 The total is 80
Ein anderes Hinweiszeichen …
§ Setzen Sie den Sentinel auf -1:
Scanner console = new Scanner(System.in);
int sum = 0;
int number = 1; // "dummy value", anything but -1 while (number != -1) {
System.out.print("Enter a number (-1 to quit): ");
number = console.nextInt();
sum = sum + number;
}
System.out.println("The total is " + sum);
§ Jetzt ist das Result falsch. Warum?
The total was 79
Das Problem mit diesem Programm
§ Unser Programm folgt diesem Muster:
summe = 0.
while (input ist nicht der sentinel) { drucke prompt; lese input.
addiere input zu summe.
}
§ Beim letzten Durchlauf durch den Rumpf wird der Sentinel -1 zur Summe addiert:
Das Problem mit diesem Programm
§ Beim letzten Durchlauf durch den Rumpf wird der Sentinel -1 zur Summe addiert:
drucke prompt; lese input (-1).
addiere input (-1) zu summe.
§ Beispiel inkorrekter Terminierung (off-by-one error, Zaunpfahlproblem):
§ Müssen N Zahlen lesen aber nur die ersten N-1 addieren.
Lösung
summe = 0.
drucke prompt; lese input. // setzen eines pfostens
while (input ist nicht der sentinel) {
addiere input zu summe. // installation querstrebe drucke prompt; lese input. // setzen eines pfostens }
§ Schleifen mit einem Sentinel folgen oft diesem Muster.
Beispiel mit Sentinel
Scanner console = new Scanner(System.in);
int sum = 0;
// pull one prompt/read ("post") out of the loop System.out.print("Enter a number (-1 to quit): ");
int number = console.nextInt();
while (number != -1) {
sum = sum + number; // moved to top of loop System.out.print("Enter a number (-1 to quit): ");
number = console.nextInt();
}
System.out.println("The total is " + sum);
do/while Schleife
§ do/while Schleife: Führt den test am Ende des Schleifenrumpfes aus um zu entscheiden, ob ein weiterer Durchlauf nötig ist
§ Stellt sicher dass der Rumpf { … } mindestens einmal ausgeführt wird.
do {
statement(s);
} while (test);
Anweisung(en) im Loop ausfuehren
Ist test wahr?
Anweisung nach Loop ausfuehren
ja
nein
do/while Schleife
Nochmal Beispiel
// Add numbers till -1 is entered
Scanner console = new Scanner(System.in);
int sum = 0;
// first round nothing to add int number = 0;
do {
sum = sum + number;
System.out.print("Enter a number (-1 to quit): ");
number = console.nextInt();
} while (number != -1);
System.out.println("The total is " + sum);
Anweisung(en) im Loop ausfuehren
Ist test wahr?
Anweisung nach Loop ausfuehren
ja
nein