Programmieren I Kapitel 5. Kontrollfluss
Kapitel 5: Kontrollfluss Ziel: Komplexere Berechnungen im Methodenrumpf Ausdrücke und Anweisungen Fallunterscheidungen (if, switch) Wiederholte Ausführung (for, while)
Wiederholung Programme bestehen aus Klassen; eine davon mit einer Methode main Klassen haben Attribute und Methoden im Methodenrumpf bisher nur Folgen von Anweisungen, die der Reihe nach abgearbeitet wurden (Ausnahme: Methodenaufrufe) heute wird es Konzepte geben, die Abarbeitungsreihenfolge flexibler zu machen dazu: Begriffe ordnen für Sachen, die wir schon kennen: Zuweisung, Anweisung, Ausdrücke, Blöcke
Ausdrücke Ausdrücke repräsentieren Werte Beispiele für Ausdrücke Literale (konstante Werte, z.b. Zahlen), Konstanten (final) oder Variablen sind gleichzeitig auch Ausdrücke binäre Infix Operatoren (z.b. +,, /, <, ==) oder auch unäre Präfix Operatoren (z.b., ~): ihr Ergebnis ist der Wert des Ausdrucks Funktionsaufrufe: das berechnete und zurückgegebene Funktionsergebnis ist der Wert des Ausdrucks mit new generierte neue Objekte: das generierte Objekt ist der Wert des Ausdrucks
Ausdrücke Ausdrücke repräsentieren Werte Beispiele, in denen Ausdrücke vorkommen: auf der rechten Seite einer Zuweisung x = <<Ausdruck>> als Argumente von binären Infix Operatoren (z.b. +,, /, <, ==) <<Ausruck>> <<Ausdruck>> als Argumente von unären Präfix Operatoren (z.b., ~) <<Ausdruck>> als aktuelle Parameter im Methodenaufruf f (<<Ausdruck 1 >>,..., <<Ausdruck n >>)
Operatoren Präzedenz Operator Beschreibung Arithmetische Operationen 1 +x, x unäres Plus/Minus 2 x*y, x/y, x%y Multiplikation, Division, Rest 3 x+y, x y Addition, Subtraktion 5 x<y, x<=y, x>y, x>=y Größenvergleiche 6 x == y, x!= y Gleichheit, Ungleichheit Operationen auf ganzen Zahlen und Booleschen Werten 1 ~x (nur auf Zahlen) bitweises Komplement NOT 7 x & y bitweises AND 8 x ^ y bitweises XOR 9 x y bitweises OR
Operatoren Präzedenz Operator Beschreibung Operationen auf Booleschen Werten 1!x NOT 10 x && y sequenzielles AND 11 x y sequenzielles OR Operationen auf ganzen Zahlen 4 x << y Linksshift 4 x >> y Rechtsshift (vorzeichenkonform) 4 x >>> y Rechtsshift (ohne Vorzeichen) Operationen auf Strings 3 x + y Konkatenation
Operatoren und ihre Präzedenz Beispiel: b & ~ a == 1 x + 3 * y >= z & x < y implizite Klammerung: ( b & ((~ a) == 1) ) ( (x + ((( 3) * y) >= z)) & (x < y))
Anweisungen Anweisungen sind auszuführende Befehle Beispiele: Zuweisungen (x =...;) Prozeduraufrufe (Terminal.println(...);) Variablendeklarationen (int i, j=...;) Rückgabeanweisungen in Funktionen (return...;) sie enden in Java alle mit einem Strichpunkt durch { zusammengefasste Blöcke von Anweisungen sind selber wieder eine Anweisung (z.b. auch Methodenrümpfe)
Abkürzende Notation für spezielle Zuweisungen Kurzform i++; (++i;) i = i + 1; i ; ( i;) i = i 1; äquivalente Langform i += 5; i = i + 5; oder allgemein i = 7; i = i 7; Das Muster = funktioniert nicht nur für + statt, sondern auch für, *, /, %, <<, >>, >>>, &, Sie werden aber nur bedingt empfohlen. Mehrfachzuweisungen sind eher als negativ Beispiel zu sehen: i = j = i + 1; j = i + 1; i = j;
Fallunterscheidungen mit if Format: es gibt zwei Möglichkeiten: if ( <<Bedingung>> ) { <<Anweisungen>> if ( <<Bedingung>> ) { <<Anweisungen>> else { <<Anweisungen>> // then Teil // then Teil // else Teil Bemerkung: die { dürfte man weglassen, wenn der then bzw. else Teil nur ein Statement umfasst das soll aber bitte nie gemacht werden.
Fallunterscheidungen mit if Beispiel: int max ( int a, int b) { if (a>=b) { return a; else { return b;
Fallunterscheidungen mit if Beispiel Notenberechnung void benotung (int punkte) { int note; if (punkte >= 87) { note = 1; else if (punkte>=75) { note = 2; else if (punkte>=63) { note = 3; else if (punkte>=51) { note = 4; else { note = 5; Terminal.println( Note: + note); Terminal.print( Die Klausur ist ); if (note > 4) { Terminal.print( nicht ); Terminal.println( bestanden. );
Fallunterscheidungen mit switch Format: switch ( <<Ausdruck>> ) { case <<Wert 1 >> : <<Anweisungen 1 >> break; case <<Wert 2 >> : <<Anweisungen 2 >> break;... case <<Wert k >> : <<Anweisungen k >> break; default : <<Anweisungen k+1 >> break; Die Werte müssen ganzzahlig sein (byte,..,long)
Fallunterscheidungen mit switch Bemerkungen: der default Fall kann weggelassen werden mehrere gleich zu behandelnde Fälle können zusammengefasst werden: case <<Wert 1 >> : case <<Wert 2 >> : case <<Wert 3 >> : <<Anweisungen für1 3 >> break;... ein vergessenes break führt zu Chaos, weil die Abarbeitung einfach im nächsten Fall weitermacht keine so zentrale Rolle wie if
Fallunterscheidungen mit switch Beispiel: int tageimmonat (int monat) { int tage; switch ( monat ) { case 4 : case 6 : case 9 : case 11 : tage = 30; break; case 2 : tage = 28; break; default : tage = 31; break; return tage;
Wiederholungsanweisungen Oft muss man Anweisungen (also oft auch Blöcke) wiederholt ausführen (iterieren) entweder, bis eine bestimmte Bedingung erfüllt ist (while Schleifen, bedingte Schleifen), oder eine vorgegebene Anzahl oft (Zählschleife)
while Schleifen Format: es gibt zwei Arten: while ( << Bedingung>> ) { <<Anweisungen>> do { <<Anweisungen>> while ( << Bedingung>> ); Unterschied: die erste (übliche) Form der while Schleife überprüft erst die Bedingung und führt bei Ergebnis true den Rumpf aus; anschließend startet sie erneut mit der Bedingungsüberprüfung für die nächste Iteration. die do while Schleife führt den Rumpf mindestens einmal aus (die Anweisungen stehen vor der Überprüfung der Bedingung), am Ende wird geprüft, ob der Rumpf wiederholt werden soll.
Arten der while Schleifen im Vergleich Beide Methoden addieren die Zahlen von a bis b. Wo ist der Unterschied? int sum1(int a, int b) { int i = a; int s = 0; while (i<=b) { s = s+i; i = i+1; return s; int sum2(int a, int b) { int i = a; int s = 0; do { s = s+i; i = i+1; while (i<=b); return s;
Eine echte while Schleife Folgende Methode addiert vom Benutzer einzugebende Zahlen, so lange, bis dieser 0 als Summand eingibt die Zahl der Iterationen ist vorab also nicht bekannt. int sum3() { int i; int s = 0; do { i = Terminal.askInt( i =? ); if (i!= 0) { s += i; while (i!= 0); Terminal.println( Summe = + s);
Zählschleifen Bedingung: die Zahl der Iterationen ist zu Beginn der Schleife bekannt Format: for ( <<Initialisierungen>>; <<Abbruchtest>>; <<Schritt>> ) { <<Anweisungen>> Warnung: Java kümmert sich nicht um die Einhaltung der Bedingung (und hat somit zwar eine neue Syntax, aber keine garantierte Zählschleife) Die Initialisierung deklariert eine Variable, die nur in der Schleife sichtbar ist.
Zählschleifen Beispiel: die ersten Summationsmethoden nochmal, so wie man sie üblicherweise schreiben würde, denn die Zahl der Iterationen ist zu Beginn der Schleife bekannt: int sum4(int a, int b) { int s = 0; for (int i=a; i<=b; i++) { s += i; return s; Anmerkung: jede Zählschleife kann man als while Schleife darstellen; die Umkehrung stimmt (mit echten Zählschleifen) nicht.
Zählschleifen und Arrays Gut zusammen passen Zählschleifen und Arrays, egal, ob man Arrayelemente kumulieren will (z.b. aufsummieren oder testen, ob/wie oft ein Wert im Array enthalten ist), oder ob man die Einträge verändern oder erst generieren will. Schema: for (int i=0; i < a.length; i++) {...
Zählschleifen und Arrays Beispiel: Ist ein bestimmter Wert in einem Array von Werten enthalten? boolean has(long[] a, long x) { boolean found = false; for (int i=0; i<a.length &&!found; i++) { if (a[i] == x) { found = true; return found;
Exkurs Nur am Rande erwähnt sei die Möglichkeit, mitten im Rumpf einer Schleife ans Ende des Rumpfes zu springen und dann mit der nächsten Iteration weiterzumachen (continue;) oder sogar ganz aus der Schleife herauszuspringen (break;) Beides sollte aus Gründen der Übersichtlichkeit (und damit Fehleranfälligkeit) nur sehr begrenzt eingesetzt werden.
Zusammenfassung Ausdrücke / Anweisungen Fallunterscheidungen mit if (und switch) Schleifen mit while und for Damit haben wir alles, was man zum Programmieren wirklich braucht (zumindest aus theoretischer Sicht ; ))