wiki:Skript/2. Java/ 4. Schleifen

Version 11 (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:

  1. Initialisierung
  2. Bedingung / Zielwert
  3. Inkrement
Allgemeine Form
for (Initialisierung; Bedingung / Zielwert; Inkrement) {
  Anweisungsblock
}
Beispiele

Ausgabe der Quadratzahlen \( f(x) = x^2 \forall 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.

Java Insel

Schleifen