Dies ist eine alte Version des Dokuments!
Jetzt geht es um Schleifen. Das wird jetzt wieder so 'ne Informationsflut - also viel ausprobieren und … hoffentlich wird's euch nicht zu langweilig …
Ach ja: Dieses Thema verlangt eine hohe Abstraktionsfähigkeit1). Bitte - nein: Bitte! - lest nur dann weiter, wenn ihr auch das Gelesene bis dahin verstanden habt2).
Es gibt viele Fälle, wo beim Programmieren gewisse Prozesse wiederholt werden müssen. In diesem Fall brauchen wir Schleifen. Java bietet dafür drei mögliche Arten von Schleifen an:
Mal sehen, wie das Innere von diesen Schleifen (=Schleifenrumpf) aussieht:
Syntax:
for ( <Schleifeninitialisierung>; <Schleifenbedingung>; <Schleifenschritt> ) { : Anweisungen / Befehle; : }
Nassi-Shneiderman-Diagramm
Beispiel:
for (int i=1; i<=5; i++) { System.out.println(i); if (i == 5) { System.out.println("Fertig!"); } }
Das führt zu der Ausgabe 1, 2, 3, 4, 5 und der Nachricht "Fertig!" (untereinander). Man sieht, dass man innerhalb des Schleifenrumpfs Anweisungen nach belieben hinzufügen kann. Falls nur eine Anweisung darin ist, darf man {...}
weglassen - wie auch beim if
, was wir zuletzt gelernt haben.
Man kann auch herunterzählen, z.B. von 5 bis 1. dazu wird die Schleifeninitialisieung, der Ausdruck und der Schleifenschritt entsprechend angepasst:
for (int i=5; i>=1; i--) { System.out.println(i); }
Wie sieht's nun aus, wenn wir die Schrittweite ändern wollen, also z.B. 1, 3, 5, 7, 9, …? Tja, da sind in Java keine Grenzen gesetzt.
for (int i=1; i<=10; i=i+2) { System.out.println(i); }
Java beinhaltet andere schöne Möglichkeiten. So wie das hier:
for (char c='A'; c<='Z'; c++) { System.out.println(c); }
Und viele merkwürdigere Möglichkeiten als diese…
Die Syntax hierzu ist:
while ( <Schleifenbedingung> ) { : Anweisungen / Befehle; : }
Nassi-Shneiderman-Diagramm
Bevor der Schleifenrumpf betreten wird, wird zuerst geprüft, ob der Ausdruck (die Bedingung(en)) erfüllt ist (sind).
Falls nicht, wird der Block einfach übersprungen; anderenfalls werden alle Anweisungen darin ausgeführt. Am Ende springt man an den Anfang der Schleife und prüft die Bedingung erneut. Wenn erfüllt, wird die Schleife noch einmal ausgeführt. Wenn nicht, dann wird sie nicht mehr ausgeführt, usw. Die Logik ist folgende:
Beispiel:
int i = 1; while (i < 6) { System.out.println(i); i++; }
Man kann Bedingungen mit &&
, ||
, oder !
kombinieren.
Die Syntax:
do { : Anweisungen / Befehle; : } while ( <Schleifenbedingung> )
Im Gegensatz zu while
, wird bei do...while
die Bedingung nicht am Anfang geprüft. Die Schleife wird einfach begonnen und alle Anweisungen in der Schleife zunächst ausgeführt. Erst am Ende, wird geprüft, ob die Bedingung erfüllt ist oder nicht. Wenn ja, wird die Schleife fortgesetzt. Wenn nein, wird die Schleife beendet. Die Logik hierzu sieht so aus:
Nassi-Shneiderman-Diagramm
Beispiel:
int i = 1; do { System.out.println(i); i++; } while ( i<6 )
In allen drei Schleifen gibt es die Möglichkeit eine Endlosschleife zu erzeugen3)). Dazu muss man Bedingungen, die immer wahr (true
) ausgewertet werden, angeben. Man sollte aber wissen, dass der Schuss nach hinten losgehen kann, wenn man damit nicht vorsichtig umgeht.
Beispiele:
while ( 2<4 ) { : // blablabla... : }
2 ist immer kleiner als 4, also wird die while-Schleife zu einer Endlosschleife.
do { : // blablabla... : } while ( 10>2 )
10 ist immer größer als 2, also wird die do...while-Schleife zu einer Endlosschleife.
for (int i=1; 1>0; i++ ) { : // blablabla... : }
1 ist immer größer als 0, also wird die for-Schleife zu einer Endlosschleife.
Man kann aber auch lediglich Folgendes schreiben, wobei auch diese Beispiele zu einer Endlosschleife führen:
while (true) { : // blablabla... : }
do { : // blablabla... : } while (true)
for (int i=1;true; i++ ) { : // blablabla... : }
…oder anders herum?
Schleifen dürfen auch verschachtelt werden, soll heißen: eine for
-Schleife in einer anderen for
-Schleife, eine while
-Schleife in einer anderen while
-Schleife, usw. Man darf sogar eine der Schleifen in andere Schleifen verschachteln, wie z.B. einer for
-Schleife innerhalb einer do...while
-Schleife…. wie auch immer!
Beispiel:
do { : for (int i=1; i<5; i++ ) { : // blablabla... : } : } while (j > 2);
Absolut erlaubt.
Was ist, wenn ich mittendrin in einer Schleife aufhören will? Nichts leichter als das: benutze break
bzw. continue
.
Beispiel (break
):
for (int i=1; i<=10; i++ ) { System.out.println(i); if (i==5) { break; } } System.out.println("Fertig");
Das führt zu der Ausgabe:
1 2 3 4 5 Fertig!
Kapiert? break
bewirkt, dass die Schleife an der Stelle verlassen wird. Es wird dann mit dem ersten Befehl nach der Schleife (die verlassen wurde) fortgesezt. (Klappt auch bei while
- und do...while
-Schleifen).
Aber wie ist die Situation mit verschachtelten Schleifen? break
wirkt sich lediglich auf die innerste Schleife aus, also auf die, in dessen Schleifenrumpf sich break
befindet.
Guck dir dazu folgendes Programmstück an:
public void schleife() { for (int i=1; i<=4; i++ ) { for (int j=1; j<=5; j++ ) { System.out.println(i + " " + j); if (j==3) { break; } } System.out.println("Nächster i-Schleifendurchlauf..."); } System.out.println("Fertig"); }
Ergibt:
1 1 1 2 1 3 Nächster i-Schleifendurchlauf 2 1 2 2 2 3 Nächster i-Schleifendurchlauf 3 1 3 2 3 3 Nächster i-Schleifendurchlauf 4 1 4 2 4 3 Nächster i-Schleifendurchlauf Fertig!
Weiteres Beispiel:
public void schleife2() { for(int i=1; i<=5; i++ ) { for (int j=1; j<=3; j++ ) { System.out.println(i + " " + j); } if (i==2) { break; } } System.out.println("Fertig"); }
Ergibt:
1 1 1 2 1 3 2 1 2 2 2 3 Fertig!
break
erledigt seine Aufgabe lediglich in seinem Gültigkeitsbereich (engl.: scope, hier: der eigene Schleifenrumpf). Und wenn ich nun die Schleife nicht verlassen will, sondern nur den aktuellen Schleifendurchlauf? Dann nimmt man continue
anstelle von break
. Probier das aus, indem du jedes break
in den vorangegangenen Beispielen durch continue
ersetzt.
Beispiel (continue
):
for (int i=1; i<=10; i++ ) { if (i==5) { continue; } System.out.println(i); } System.out.println("Fertig");
Das führt zu der Ausgabe:
1 2 3 4 6 7 8 9 10 Fertig!
Bei einer continue
-Anweisung springt das Programm also an das Ende des Schleifenrumpfs und beginnt mit der nächsten Iteration.
Auch hier gilt: Falls es noch nicht geschehen sein sollte: Schreibe alle Beispielmethoden und die Beispielschleifen ab und probiere, wie es in der Beschreibung empfohlen wird, ein wenig damit aus.
Teil I : Theorie (müsste in 30 Minuten zu lösen sein)
Teil II : Praktisch
In diesem II. Teil werden einige Beispielein- und ausgaben gegeben. Du musst eine Methode mit einer der Schleifen schreiben. Die Wahl liegt bei dir. Solange die Programme laufen, ist's in Ordnung. Tipp: Bevor du mit diesem Teil anfängst, solltest Du erst üben!
Eingabe: 5 Ausgabe: 1 2 3 4 5 4 3 2 1 Eingabe: 1 Ausgabe: 1
Eingabe: 5 Ausgabe: 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
Eingabe: 5 Ausgabe: 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5
Eingabe: 5 Ausgabe: 1 2 3 4 5 2 3 4 5 1 3 4 5 1 2 4 5 1 2 3 5 1 2 3 4
Eingabe: 5 Ausgabe: 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
Eingabe: 5 Ausgabe: 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5
Eingabe: 5 Ausgabe: 1 1 2 1 1 2 3 2 1 1 2 3 4 3 2 1 1 2 3 4 5 4 3 2 1 1 2 3 4 4 4 4 4 3 2 1 1 2 3 3 3 3 3 3 3 3 3 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Eingabe: 5 Ausgabe: 1 1 1 1 1 1 2 2 2 1 1 2 3 2 1 1 2 2 2 1 1 1 1 1 1
Eingabe: 10 Ausgabe: 1 1 2 3 5 8 13 21 34 55
Die ersten beiden Fibonaccizahlen sind 1. Die dritte ist die Summe der ersten beiden. Die vierte die Summe der zweiten und der dritten, usw. die n-te die Summe der (n-1)-ten und (n-2)-ten.