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 vector = new Vector();

// 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 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 set = new HashSet();
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 list = new ArrayList();
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.

Categories: Java

14 Comments

Denzo · July 1, 2012 at 3:52 pm

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

Hope · January 25, 2013 at 4:04 am

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

Pheobe · February 27, 2013 at 7:57 pm

Gute erklärung!

Dennis · December 21, 2013 at 1:50 pm

Klasse Post!

Ich schreibe leichte Java-Übungsaufgaben und referenziere auf diesen Beitrag für mehr Infos zu for-Schleifen, weil diese Erklärung wirklich gut zugänglich geschrieben ist.

Zwei von zwei Daumen! ^^

peter · April 2, 2014 at 1:57 pm

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 ?

JavaExperte · April 23, 2014 at 3:15 am

Super! Hat mir sehr geholfen!

fasf · July 26, 2014 at 12:14 pm

Nice one, thx!

Norbert · November 7, 2014 at 1:34 pm

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.

Norbert · November 7, 2014 at 2:01 pm

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.

Hans · March 31, 2015 at 9:28 am

man ist als entwickler quasi nie am index der laufvariablen interessiert? dann sollte man mal versuchen ohne index werte zu ändern…

Joachim · July 7, 2015 at 3:48 pm

@Norbert:

nein, das ist schon richtig, denn man kann die Komponenten eines Statements mit Hilfe von Komma als Sequenz formulieren, die mit Semikolon dann abgeschlossen wird.
for( int i=0, j=1; i<ende; ++i, ++j) ;
ist legal.

Fabian · October 10, 2015 at 11:36 am

@peter:

Nein, die for-Schleife würde nicht bis 11 zählen, da 11 > 10. <= 10 bedeutet das nicht wie bei Ausgabe: 5
2. Durchgang:
i = 6 => Ausgabe: 6
3. Durchgang:
i = 7 => Ausgabe: 7
4. Durchgang:
i = 8 => Ausgabe: 8
5. Durchgang:
i = 9 => Ausgabe: 9
6. Durchgang:
i = 10 => Ausgabe: 10

7. Durchgang:
i = 11 => keine Ausgabe, da
Bedingung “i <= 10" nicht
mehr erfüllt ist.

Testoboy · June 22, 2017 at 6:04 pm

“Wenn ich etwas vergessen habe oder einen Fehler eingebaut habt, ..” 😉 Da ist ein Fehler !

Jannik · October 11, 2017 at 2:27 pm

Jetzt, 5 Jahre später, hilft dein Beitrag immernoch Anfängern.
Vielen Dank dafür, sehr verständlich und ausführlich!

Leave a Reply

Your email address will not be published. Required fields are marked *