Schabby's Blog
Reserve Orbital Defence Commander

In diesem post widme ich mich folgender Fragestellungen:

  • Beispiele und Erklärung der For- und ForEach Schleife
  • Was ist mit For bzw. ForEach Loop gemeint?
  • Was sind Java Laufvariablen und wie benutze ich sie?

Es werden erst die klassische For-Schleifen besprochen, bevor wir uns den moderneren For-Each Schleifen widmen.

Einführung und Definition

Die For-Schleife dient zum wiederholten ausführen eines Code-Blocks, wobei in jeder Iteration ein Schritt-Operation (zB. Hochzählen einer Variable) ausgeführt wird. Etwas weniger allgemein formuliert kann man sagen, dass sie zum Hoch- oder Runterzählen von Variablen verwendet werden kann. Der englische Begriffe der Schleife ist Loop, daher sind beide Begriffe synonym zu verstehen.

Das folgende Beispiel zählt die variable i von 5 bis 10 hoch:

int i; // die Laufvariable
for(i = 5; i <= 10; i = i + 1)
{
    // ausgeführter Code der die Laufvariable i verwenden kann, zB.
    System.out.println("i = "+i);
}

Wir sehen, dass in dem eingeklammerten Teil vor dem for etwas kryptisches stehts, was offensichtlich zum Verwenden der For-Schleife nötig ist. Dieser Teil läßt sich in drei Teile zerlegen, die jeweils mit einem Semmikolon getrennt sind:

for( Start ; Ende ; In-/Dekrementieren )

Im obigen Beispiel ist besteht der erste Teil (Start) aus dem setzen des Startwertes i = 5, also dass die Schleife bei 5 anfangen soll zu zählen. Häufig wird an dieser Stelle die Deklaration der Variable Der zweite Teil ist das Abbruchkriterium, nämlich i <= 10, was so viel heißt wie, dass i solange hochgezählt wird, bis i kleiner-gleich 10 ist. Der dritte Teil besagt was nach jeder Iteration passieren soll. In diesem Fall wird i um 1 erhöht. Eine häufige Notation die man an dieser Stelle sieht ist i++, was einfach nur eine Kurzform von i = i + 1 ist. Entsprechend ist übrigens i-- nur die Kurzform von i = i - 1. Ein weiteres Beispiel einer For-Schleife sie wie folgt aus:

for(int i = 10; i >= 5; i--)
{
    // ausgeführter Code der die Laufvariable i verwenden kann, zB.
    System.out.println("i = "+i);
}

Diese Schleife zählt ganz offensichtlich runter von 10 auf 5. In diesem Beispiel deklarieren wir i "inline" gleich mit in der Start-Definition der For-Schleife. Das spart uns eine Zeile vorher und es ist klar, dass i nur im Scope des Schleifen-Blocks liegt. Die Definition der Abbruchbedingung ist entsprechend abgewandelt zum ersten Beispiel. Der letzte Teil ist die dekrementierung von i.

Generell kann man also den eingeklammerten Teil der Schleifendefinition wie folgt lesen:

for( Starte bei i=10 und führe ; solange wie i>=5 gilt, ; den Code i-- aus )

Der Unterschied zu einer while-Schleife liegt also darin, dass im eingeklammerten Teil nicht nur die Abbruchbedingung festgelegt wird.

Schleifen können auch verschachtelt werden und so ist es nicht unüblich, dass man zum iterieren über Bilder oder Matrizen zwei For-Schleifen anwendet um mit zwei Laufvariablen einen 2-Dimensionalen Raum abzuwandern. Im folgenden Beispiel iterieren wir über das Google Logo und geben dabei Pixelweise die Farbe aus:

// lade Google Logo
BufferedImage image = ImageIO.read(new URL("http://www.google.de/images/srpr/logo3w.png"));
 
// x iteriert über die Breite des Bildes
for( int x = 0; x < image.getWidth(); x++ )
{
	// y iteriert über die Höhe des Bildes
	for( int y = 0; y < image.getHeight(); y++ )
	{
		// Gib Pixelfarben als Red, Green, Blue, alpha Komponenten auf der Konsole aus.
		int red   = image.getColorModel().getRed(image.getRGB(x, y));
		int green = image.getColorModel().getGreen(image.getRGB(x, y));
		int blue  = image.getColorModel().getBlue(image.getRGB(x, y));
		int alpha = image.getColorModel().getBlue(image.getRGB(x, y));
		System.out.println("Position ("+x+", "+y+"): ["+red+","+green+","+blue+","+alpha+"]");
	}
}

Natürlich können auch andere Werte als Zahlen als Laufvariabe und zur Iteration verwendet werden. So war es früher beispielsweise üblich, dass man Iterator-Objekte verwendete, die den aktuellen Status der Laufvariable wiederspiegelte und mit denen über unterschiedliche Datenstrukturen iteriert werden konnte. Im Prinzip speichern solche Iterator Objekte intern auch nur einen index ab, an welcher Stelle man sich aktuell in der Datenstruktur befindet. Ein Beispiel macht deutlich, was gemeint ist:

// dynamische Liste, so wie sie früher häufig verwendet wurde
Vector<String> vector = new Vector<String>();
 
// wir hängen ein paar Namen an die Liste an
vector.add("Peter");
vector.add("Klaus");
vector.add("Frieda");
vector.add("Manfred");
 
// Vector.iterator() gibt ein Objekt vom Type Iterator zurück
for( Iterator<String> it = vector.iterator(); it.hasNext(); )
{
	// it.next() holt den nächsten Wert aus dem Vector ab
	System.out.println(it.next());
}

Die Ausgabe ist erwartungsgemäß:

Peter
Klaus
Frieda
Manfred

Das interessant an diesem Beispiel ist, dass der letzte Part des in Klammern eingeschlossenen Teils leer bleibt. Das heißt es gibt keinen Iterationsteil. Dieser wird nämlich im For-Block selbst ausgeführt (it.next()).

So weit, so gut. Wollen wir nun zum nächsten Level vordringen.

ForEach Schleifen mit Beispielen

For-Each Schleifen funktionieren ganz ähnlich wie die gewöhnlichen For-Schleifen und sind quasi eine Weiterentwicklung. Im Gegensatz zu den normalen, verwenden ForEach Schleifen aber keine nach außen sichtbare Laufvariable oder Iterator-Objekt, sondern gibt in jeder Iteration immer direkt den Wert zurück. Das heißt aber auch, dass immer über eine entsprechende Datenstruktur iteriert werden muss die das ermöglicht. Schauen wir uns ein Beispiel an:

// definition eine Datenstruktur, hier ein Array mit 9 Werten
int[] array = new int[]{4, 8, 4, 2, 2, 1, 1, 5, 9};
 
// ForEach Schleife
for( int k: array )
{
	System.out.println("k = "+k);
}

Die Ausgabe ist

k = 4
k = 8
k = 4
k = 2
k = 2
k = 1
k = 1
k = 5
k = 9

Man sieht also, dass k nicht die Laufvariable hält, sondern den direkten Wert. ForEarch iteriert also über alle Elemente und ruf den Block auf. Daher kann auch der Name abgeleitet werden: For Each element, do this and that. Intern wird dennoch ein Iterator-Objekt gehalten in dem der State der Iteration festgehalten wird. Da man als Entwickler aber quasi nie am Index der Laufvariable interessiert ist, sondern eigentlich nur an den Werten, macht ForEach jede Menge Sinn. Ein paar Beispiele für weitere Verwendungen von ForEach-Schleifen:

Set<String> set = new HashSet<String>();
set.add("Peter");
set.add("Frieda");
set.add("Manfred");
 
for(String name: set) System.out.println(name);

In diesem Beispiel ist die Reihenfolge der Ausgabe nicht definiert, da es sich um eine Menge (Set) handelt und nicht um eine Liste oder andere order-preserving Datenstruktur. Das Gegenbeispiel dazu ist die Verwendung der ArrayList:

List<String> list = new ArrayList<String>();
list.add("Peter");
list.add("Frieda");
list.add("Manfred");
 
for(String name: list) System.out.println(name);

Und das wars :) Ich denke Ihr habt nun eine sehr gute Vorstellung davon wie diese Schleifen zu verwenden sind. Wenn ich etwas vergessen habe oder einen Fehler eingebaut habt, laßt es mich bitte wissen. Wenn Euch der Post gefallen, dann laßt auch gern einen Kommentar da.


8 Antworten

  1. Denzo says:

    Super Artikel!
    Bin gerade am lernen für Java Klausuren und da kommt mir so eine gute Erklärung der ForEach - Schleife gerade recht.

  2. Hope says:

    Vielen Dank für die ausfürliche und einfache Erklärungen! Hat mir sehr geholfen

  3. Pheobe says:

    Gute erklärung!

  4. peter says:

    int i; // die Laufvariable
    for(i = 5; i <= 10; i = i + 1)
    {
    // ausgeführter Code der die Laufvariable i verwenden kann, zB.
    System.out.println("i = "+i);
    }

    Würde hier nicht bis 11 gezählt werden weil i <= 10 ?

  5. JavaExperte says:

    Super! Hat mir sehr geholfen!

  6. fasf says:

    Nice one, thx!

  7. Norbert says:

    Danke für diesen sehr anschaulichen Artikel!

    Als eifriger Haarspalter möchte ich noch folgendes Detail präzisieren:

    for ( Start ; Ende ; In-/Dekrementieren )

    Die Teile eins und drei werden lediglich per Konvention zur Initialisierung und zum Inkrementieren/Dekrementieren der Laufvariable verwendet, nicht aber per Sprachdefinition. Genau betrachtet heißt es:

    for ( Code vor Schleifen-Eintritt ; Endebedingung ; Code am Ende jeden Durchgangs )

    Teile eins und drei können auch völlig abwegige Statements beherbergen, die überhaupt nichts mit einem Schleifenzähler zu tun haben. Sie könnten in geschweiften Klammern jeweils sogar einen ganzen Block beliebiger Befehle ausführen.

    Die Endebedingung muß lediglich einen Boolean zurückliefern, sie muß ansonsten auch nicht unbedingt mit der Schleife zu tun haben.

    Und auch die folgende völlig korrekte Sequenz sollte jeder mal gesehen haben:

    for ( ; ; ) { }

    Das wars. Viele Grüße.

  8. Norbert says:

    p.s.

    Oops, in obigem Kommentar die Zeile

    for ( Code vor Schleifen-Eintritt ; Endebedingung ; Code am Ende jeden Durchgangs )

    soll besser lauten:

    for ( Befehl vor Schleifen-Eintritt ; Endebedingung ; Befehl am Ende jeden Durchgangs )

    denn in Teil 1 und 3 darf je genau 1 Befehl stehen, nicht aber 'Code', was ja mehrere Befehle bedeuten könnte.

    Vielleicht kann der Moderator das ja einfach korrigieren, und dann diesen Kommentar hier löschen.

    Danke.

Post Comment

Please notice: Comments are moderated by an Admin.