Programmiertechnik Kontrollstrukturen Prof. Dr. Oliver Haase Oliver Haase Hochschule Konstanz 1
Was sind Kontrollstrukturen? Kontrollstrukturen erlauben es, ein Programm nicht nur Zeile für Zeile auszuführen, sondern in Abhängigkeit bestimmter Bedingungen bestimmte Programmteile auszuführen. Siehe z.b. folgende (Kontroll-)Flussdiagramme: Anweisung Entscheidung Anweisung Schleife Bedingung? false Bedingung? false true true Anweisung Anweisung Anweisung Anweisung Anweisung Anweisung Anweisung Anweisung Oliver Haase Hochschule Konstanz 2
Überblick Kontrollstrukturen steuern den Ablauf eines Programms. Kontrollstrukturen sind spezielle Arten von Anweisungen. In Java (wie in den meisten Programmiersprachen) gibt es verschiedene Arten von Anweisungen: Deklarationsanweisungen Zuweisungsanweisungen Methodenaufruf Blöcke If-Anweisungen Switch-Anweisungen Schleifen Sprünge hier behandelt Oliver Haase Hochschule Konstanz 3
Blöcke Ein Block ist eine mit { und geklammerte Folge von Anweisungen. Ein Block kann überall dort wo eine Anweisung erlaubt/erfordert ist, als eine einzige Anweisung eingesetzt werden. Innerhalb eines Blocks können auch Variablen deklariert werden, deren Gültigkeit auf den Block beschränkt ist. int i = 1; { { int j = 2; System.out.println(i +j); int j = 3; System.out.println(i +j); Blöcke Oliver Haase Hochschule Konstanz 4
If-Anweisung Die If-Anweisung ist die fundamentalste aller Kontrollanweisungen if (<Bedingung>) <Anweisung> else <Anweisung> Syntaxregel <Bedingung> ist ein Ausdruck, der ein Ergebnis vom Typ boolean liefert, z.b. boolsche Variable, logische Operation, oder Vergleich. Auswertung: <Bedingung> falls <Bedingung> true liefert, dann unmittelbar folgende Anweisung falls <Bedingung> false liefert, dann Anweisung unmittelbar nach else. Oliver Haase Hochschule Konstanz 5
If-Anweisung Beispiel Betragsberechnung: double x, y; java.util.scanner scanner = new java.util.scanner(system.in); System.out.print("x:"); x = scanner.nextdouble(); if (x < 0.0) y = -x; else y = x; System.out.println("Der Betrag von " + x + " ist " + y); Merke: Nur die Anweisung unmittelbar nach else gehört zum 'Sonst'-Fall, die Bildschirmausgabe nicht mehr! Oliver Haase Hochschule Konstanz 6
If-Anweisung Der else-teil kann komplett fehlen: if (<Bedingung>) <Anweisung> Syntaxregel Beispiel Betragsberechnung 2: double x, y; java.util.scanner scanner = new java.util.scanner(system.in); System.out.print("x:"); x = scanner.nextdouble(); y = x; if (x < 0.0) y = -x; System.out.println("Der Betrag von " + x + " ist " + y); Oliver Haase Hochschule Konstanz 7
If-Anweisung Die Anweisungsteile können selbst Blöcke sein. Damit ergibt sich die Form: if (<Bedingung>) { <Anweisung> <Anweisung> else { <Anweisung> <Anweisung> Syntaxregel Oliver Haase Hochschule Konstanz 8
If-Anweisung Es ist guter Stil, selbst einzelne Anweisungen zu klammern, um Fehler zu vermeiden (defensives Programmieren). Siehe folgendes Beispiel. Was ist hier falsch? int x = scanner.nextinteger(); if (x == 0) { System.out.println("x ist gleich 0"); else System.out.println("x ungleich 0, wir dividieren"); System.out.println("1/x liefert " + 1 / x); Oliver Haase Hochschule Konstanz 9
Switch-Anweisung Ebenso wie die If-Anweisung eine Entscheidungsanweisung. Erlaubt, in verschiedene Alternativen zu verzweigen switch (<Ausdruck>) { case <Konstante>: <Anweisungsfolge> break; case <Konstante>: <Anweisungsfolge> break; default: <Anweisungsfolge> Syntaxregel Oliver Haase Hochschule Konstanz 10
Switch-Anweisung <Ausdruck> muss byte, short, int, oder char liefern. Wenn Auswertung von <Ausdruck> den Wert <Konstante> liefert, wird die entsprechende <Anweisungsfolge> ausgeführt. Beachte: <Anweisungsfolge>, im Unterschied zu einem Block, muss nicht geklammert werden! Wenn Wert von Ausdruck nicht gefunden wird, wird <Anweisungsfolge> hinter default-marke ausgeführt. Die default-marke kann fehlen, dann wird im obigen Fall gar nichts ausgeführt. Oliver Haase Hochschule Konstanz 11
Switch-Anweisung Beispiel: char result; // result wird ein Character zugewiesen switch (result) { case '+': System.out.println("gutes Ergebnis"); break; case '-': System.out.println("schlechtes Ergebnis"); break; case 'o': System.out.println("So-la-la-Ergebnis"); break; default: System.out.println("unbekanntes Ergebnis"); Oliver Haase Hochschule Konstanz 12
Switch-Anweisung Wenn break-anweisung fehlt, wird die Ausführung fortgesetzt bis ein break erreicht wird engl: Fall-Through. Praktisch, wenn mehrere Werte denselben Effekt haben sollen: char result; // result wird ein Character zugewiesen switch (result) { case 'o': case '+': System.out.println("bestanden"); break; case '-': System.out.println("durchgefallen"); break; default: System.out.println("unbekanntes Ergebnis"); Oliver Haase Hochschule Konstanz 13
Switch-Anweisung Ein vergessenes break ist aber auch eine häufige Fehlerursache: int a, b; a = scanner.nextinteger(); switch (a) { case 1: b = 10; case 2: case 3: b = 20; break; default: b = 40; Welchen Wert erhält b für verschiedene Werte von a? Oliver Haase Hochschule Konstanz 14
Schleifen Schleifen erlauben es, eine Anweisung (einen Block von Anweisungen) mehrmals zu durchlaufen. Java kennt 3 Arten von Schleifen: For-Schleifen While-Schleifen Do-Schleifen Allen Schleifenarten ist gemeinsam, dass sie eine Abbruchbedingung enthalten. Oliver Haase Hochschule Konstanz 15
For-Schleife Syntaxregel for (<Initialisierung>; <Bedingung>; <Update>) <Anweisung> Auswertung: 1. Mit Hilfe der <Initialisierung> wird eine Schleifenvariable deklariert und initialisiert, z.b. int i = 0 2. Die <Bedingung>, die üblicherweise die vorher initialisierte Variable enthält, wird ausgewertet. Beispiel: i < 10 3. Falls Schritt 2 false ergibt, wird die Schleife beendet 4. Falls Schritt 2 true ergibt, wird a) <Anweisung> ausgeführt b) <Update> ausgeführt, z.b. i++ c) mit Schritt 2 fortgefahren Oliver Haase Hochschule Konstanz 16
For-Schleife Auswertung als Kontrollflussdiagramm: Initialisierung Bedingung? false true Anweisung Update Oliver Haase Hochschule Konstanz 17
For-Schleife Beispiel: for ( int i = 0; i < 10; i++ ) System.out.println("i: " + i); <Anweisung> -- der Schleifenrumpf kann ein geklammerter Block von Anweisungen sein. Ebenso wie bei der If-Anweisung ist es guter Stil, den Schleifenrumpf immer zu klammern. ( Warum?) Oliver Haase Hochschule Konstanz 18
For-Schleife Jeder Bestandteil des Schleifenkopfs (Initialisierung, Bedingung, Update) kann fehlen keine Bedingung entspricht true Beispiel int i = 0; for ( ; i < 10; ) { System.out.println("i: " + (i++)); Oliver Haase Hochschule Konstanz 19
For-Schleife Der geklammerte Anweisungsblock im Schleifenrumpf kann selbst wieder eine Schleife sein: for ( int i = 0; i < 10; i++ ) { for ( int j = 0; j < i; j++ ) { System.out.println("(" + i + ", " + j + ")"); Oliver Haase Hochschule Konstanz 20
While-Schleife Die While-Schleife ist allgemeiner (flexibler) als die For-Schleife. while (<Bedingung>) <Anweisung> Syntaxregel Auswertung: 1. <Bedingung> wird ausgewertet 2. Falls Auswertung false ergibt, wird die Schleife beendet 3. Falls Auswertung true ergibt, wird a) <Anweisung> ausgeführt b) mit Schritt 1 fortgefahren Oliver Haase Hochschule Konstanz 21
While-Schleife Auswertung als Kontrollflussdiagramm: Bedingung? false true Anweisung Oliver Haase Hochschule Konstanz 22
While-Schleife Natürlich kann der Schleifenrumpf ein geklammerter Block von Anweisungen sein. Bei der While-Schleife muss der Programmierer die Schleifenvariable ggf. selbst deklarieren, initialisieren und im Schleifenrumpf aktualisieren. Beispiel: int i = 0; while ( i < 10 ) { System.out.println("i: " + i); i++; Auch hier ist es guter Stil, den Schleifenrumpf immer zu klammern! Oliver Haase Hochschule Konstanz 23
While-Schleife Jede For-Schleife kann durch eine While-Schleife ersetzt werden. for (<Initialisierung>; <Bedingung>; <Update>) <Anweisung> <Initialisierung>; while (<Bedingung>) { <Anweisung>; <Update>; Oliver Haase Hochschule Konstanz 24
Do-Schleife Ähnlich wie While-Schleife, nur dass Bedingung erst nach Ausführung des Rumpfs getestet wird Schleife wird mindestens einmal durchlaufen. do <Anweisung> while (<Bedingung>); Syntaxregel Auswertung: 1. <Anweisung> wird ausgeführt 2. <Bedingung> wird ausgewertet 3. Falls Auswertung false ergibt, wird die Schleife beendet 4. Falls Auswertung true ergibt, wird mit Schritt 1 fortgefahren Oliver Haase Hochschule Konstanz 25
Do-Schleife Auswertung als Kontrollflussdiagramm: Anweisung Bedingung? false true Oliver Haase Hochschule Konstanz 26
Do-Schleife Natürlich kann der Schleifenrumpf ein geklammerter Block von Anweisungen sein. Genauso wie bei der While-Schleife muss der Programmierer die Schleifenvariable selbst deklarieren, initialisieren und im Schleifenrumpf aktualisieren. Beispiel: int i = 0; do { System.out.println("i: " + i); i++; while ( i < 10 ); Auch hier ist es guter Stil, den Schleifenrumpf immer zu klammern! Oliver Haase Hochschule Konstanz 27
Do-Schleife Jede Do-Schleife kann durch eine While-Schleife ersetzt werden. do <Anweisung> while (<Bedingung>); <Anweisung>; while (<Bedingung>) <Anweisung>; Oliver Haase Hochschule Konstanz 28
Endlosschleife Wenn die Schleifenbedingung niemals false ergibt, liegt eine Endlosschleife vor. Endlosschleifen können absichtlich, aber auch versehentlich programmiert werden. Beispiel für absichtliche Endllosschleife: while (true) { System.out.println("Nochmal!"); Oliver Haase Hochschule Konstanz 29
Endlosschleife Unabsichtliche Endlosschleifen resultieren meist daraus, dass vergessen wird die Schleifenvariable im Schleifenrumpf zu verändern. Beispiel für unabsichtliche Endllosschleife: int i = 0; while (i < 10) { System.out.println("i: " + i); Oliver Haase Hochschule Konstanz 30
Sprünge In Java gibt es keine goto-anweisung! Es gibt nur zwei eingeschränktere Sprungvarianten, nämlich: break um eine Schleife (oder eine Switch-Anweisung) zu verlassen continue um zur Schleifenbedingung zu springen Oliver Haase Hochschule Konstanz 31
Break Bereits zusammen mit Switch-Anweisung kennengelernt Springt aus innerster Schleife Wird meistens verwendet, um Schleife vorzeitig zu verlassen. Beispiel: int product = 1; for ( int i = 1; i < 20; i++) { product *= i; if ( product > 1000000 ) { break; System.out.println(product); Oliver Haase Hochschule Konstanz 32
Break Merke: break kann immer durch geeignete Schleifenbedingung ersetzt werden! Beispiel: int i = 1; int product = 1; do { product *= i; i++; while ((i < 20) & ( product <= 1000000)); System.out.println(product); Oliver Haase Hochschule Konstanz 33
Continue Springt zum innersten Schleifenkopf Sinnvoll, um Schleifenausführung für bestimmte Sonderfälle zu vermeiden. Beispiel: for ( int i = -10; i <= 10; i++ ) { if ( i == 0 ) { continue; System.out.println("1/" + i + "= " + 1/i); Oliver Haase Hochschule Konstanz 34