Version 9 (modified by tr, 8 years ago) (diff) |
---|
Schleifen
Auf Schleifen greift man in der Programmierung dann zurück, wenn Programmteile wiederholt ausgeführt werden sollen. Der zu wiederholende Programmteil wird dazu in einen Anweisungsblock eingeschlossen. Dieser Anweisungsblock wird auch Schleifenkörper genannt. Durch die Auswertung einer Bedingung wird entschieden, ob der Schleifenkörper ausgeführt wird (Wert der Bedingung ist true) oder nicht ausgeführt wird (Wert der Bedingung ist false).
In den meisten Fällen ist es erwünscht, dass die Schleife wieder verlassen werden kann (die Bedingung nimmt den Wert false an). Daher ist es üblicherweise notwendig, dass im Schleifenkörper mindestens eine der in der Bedingung verwendeten Variablen verändert wird. In manchen Fällen sind Bedingungen so beschaffen, dass sie Daten auswerten, die nicht durch das Programm modifiziert werden, wie z. B. Sensordaten (Position, Umgebungslicht, Systemzeit, usw.). Derartige Bedingungen spielen in dieser Lehrveranstaltung keine Rolle.
In Java gibt es - wie in den meisten Programmiersprachen - drei wesentliche Schleifentypen:
- kopfgesteuerte Schleifen
- fußgesteuerte Schleifen
- Zählschleifen
while-Schleife
while-Schleifen sind kopfgesteuerte Schleifen, weil die Bedingung, die über den Eintritt in den Schleifenkörper entscheidet, am Anfang der Schleife, am Kopf, notiert wird. Der Schleifenkörper wird ausgeführt so lange die Bedingung den Wert true hat.
- Allgemeine Form
while (Bedingung) { Anweisungsblock // Variable aus der Bedingung sollte verändert werden }
- Beispiele
Berechnung von 2n.
int n = scan.nextInt(); int i = 1; int y = 1; // Falls eine Zahl < 1 für n eingegeben wird, wird die Schleife nie betreten. // Das kann durchaus erwünschtes Verhalten des Programms sein. while (i <= n) { y = y * 2; i++; }
Aufsummieren von durch Benutzer eingegebene Zahlen bis eine 0 eingegeben wird.
// Benutzereingabe int zahl; // Zwischenergebnis int summe = 0; zahl = scan.nextInt(); while (zahl != 0) { summe = summe + zahl; zahl = scan.nextInt(); } System.out.println("Summe: " + summe);
Im obigen Beispiel finden sich zwei Muster:
- die Zeile int summe = 0; initialisiert das Ergebnis der Berechnung, das während der folgenden Schleifendurchläufe immer aktualisiert wird und nach Verlassen der Schleife das Endergebnis enthält.
- Die Zeile zahl = scan.nextInt(); ist zweimal notiert. Die Struktur der Schleife erfordert diese Konstruktion. Beim ersten Mal wird die Zahl einmalig eingelesen, damit die vor dem Schleifenkörper stehende Bedingung geprüft werden kann. Beim zweiten Mal, und das ist das eigentliche Muster, wird die Zahl eingelesen, um den nächsten Schleifendurchlauf vorzubereiten.
do-while-Schleife
do-while-Schleifen sind fußgesteuerte Schleifen, da die Bedingung, die über den (erneuten) Eintritt in den Schleifenkörper am Ende der Schleife, am Fuß, notiert wird. Der Schleifenkörper wird ausgeführt so lange die Bedingung den Wert true hat.
Der Schleifenkörper einer do-while-Schleife wird mindestens einmal ausgeführt, da die Bedingung erst am Ende erreicht und geprüft wird.
- Allgemeine Form
do { Anweisungsblock // Variable aus der Bedingung sollte verändert werden } while (Bedingung);
- Beispiel
Es sollen solange Benutzereingaben erfolgen, bis eine gültige Monatsnummer (1..12) eingegeben wurde.
int monat; do { System.out.print("Monatsnummer: "); monat = scan.nextInt(); } while (monat < 1 || monat > 12);
Bei diesem Beispiel ist zu beachten, dass die Bedingung in "umgekehrter" Logik formuliert werden muss: Die Eingabe soll wiederholt werden, so lange die Monatszahl nicht gültig ist. Es muss also eine Bedingung konstruiert werden, die bei fachlich falscher Eingabe den Wert true annimmt.
for-Schleife
for-Schleifen sind Zählschleifen: Es ist von Anfang an bekannt, wie oft die Schleife durchlaufen werden soll. Die Anzahl der Schleifendurchläufe muss dabei keine Konstante sein, sondern kann - und wird es in den meisten Fällen auch - ein berechneter Wert sein.
Im Kopf der for-Schleife werden die folgenden drei Parameter notiert:
- Initialisierung
- Bedingung / Zielwert
- Inkrement
- Allgemeine Form
for (Initialisierung; Bedingung / Zielwert; Inkrement) { Anweisungsblock }
- Beispiele
Ausgabe der Quadratzahlen f(x) = x2 für alle x in [1, 100]. Die Ausgabe soll formatiert so erfolgen, dass x und f(x) rechtsbündig in zwei Spalten nebeneinander stehen.
for (int i = 1; i <= 100; i++) { // formatierte Ausgabe, das Ergebnis wird direkt in der Ausgabe berechnet System.out.printf("%3d%7d", i, i * i); // Zeilenumbruch, könnte noch gespart werden, indem der Formatstring von printf um "\n" erweitert würde. System.out.println(); }
Beispiele für Schleifen
Grundsätzlich lassen sich die drei Schleifentypen bei identischer Funktionalität in alle anderen Schleifentypen überführen. Betrachten Sie die Berechnung der Fakultät:
Berechnung der Fakultät
Berechnung der Fakultät f(n) = 1 * 2 * .. * n mit den drei Schleifentypen:
int n = scan.nextInt(); // Zwischenspeicher für das Ergebnis; Produkte werden mit 1 initialisiert. int f = 1; for (int i = 1; i <= n; i++) { f = f * i; } System.out.println(n + "! = " + f);
int n = scan.nextInt(); // Zwischenspeicher für das Ergebnis; Produkte werden mit 1 initialisiert. int f = 1; // Schleifenzähler int i = 1; while () { f = f * i; i++; } System.out.println(n + "! = " + f);
int n = scan.nextInt(); // Zwischenspeicher für das Ergebnis; Produkte werden mit 1 initialisiert. int f = 1; for (int i = 1; i <= n; i++) { f = f * i; } System.out.println(n + "! = " + f);
Vermeiden von break und continue
Mittels break lässt sich eine Schleife beenden, ohne dass die Bedingung erneut geprüft wird. Dies wird auch als Schleifenausbruch bezeichnet:
// Summe int s = 0; for (int i = 1; i <= 10; i++) { summe = summe + i; if (summe >= 25) { // beendet die Schleife sofort break; } } // summe hat den Wert 28 // break wurde nach sieben Schleifendurchläufen aufgerufen System.out.println(summe);
Derartige Konstruktionen sind zu vermeiden, da sie die Lesbarkeit, Verständlichkeit und Wartbarkeit des Codes massiv verschlechtern. Der Befehl break kann großen Einfluss auf den Programmablauf nehmen, lässt sich jedoch sehr leicht übersehen. Falls ein vorzeitiger Schleifenabbruch erfolgen soll, sollte die Bedingung entsprechend angepasst werden:
// Summe int s = 0; int i = 1; boolean exit = false; while(i <= 10 && !exit) { summe = summe + i; i++; if (summe >= 25) { // erzwingt das Schleifenende bei der nächsten Prüfung der Bedingung exit = true; } } // summe hat den Wert 28 System.out.println(summe);
Eine ähnliche Bedeutung hat continue, das jedoch nicht den Schleifenaustritt, sondern den Abbruch des aktuellen Durchlaufs und die erneute Prüfung der Bedingung veranlasst. Die Verwendung von continue ist aus den oben genannten Gründen ebenfalls zu vermeiden.