Java for-each (Enhanced for) Schleife
Arrays und Collections in Java mit der for-each-Schleife durchlaufen – einfacher und sicherer iterieren.
Java 5 führte die erweiterte for-Schleife ein — üblicherweise for-each-Schleife genannt — um jeden Element eines Arrays oder einer Collection zu durchlaufen, ohne den Index manuell zu verwalten. Wenn man den Index nicht benötigt, ist dies fast immer die übersichtlichste Wahl.
Syntax
for (Type element : iterable) {
// body — runs once per element
}Zu lesen als: für jedes element in iterable. Der Doppelpunkt ist obligatorisch; er ist nicht dasselbe wie die Semikolons der regulären for-Schleife.
int[] nums = {10, 20, 30, 40};
for (int n : nums) {
System.out.println(n);
}Gibt 10 20 30 40 aus. Kein Zähler, kein nums.length, kein nums[i].
Funktioniert mit Arrays und jedem Iterable
Die for-each-Schleife akzeptiert:
- Jedes Array.
- Alles, was
java.lang.Iterable<T>implementiert — das bedeutet jedeCollection(wieList,SetundQueue), sowie viele andere JDK- und Bibliothekstypen.
import java.util.List;
List<String> names = List.of("alice", "bob", "carol");
for (String name : names) {
System.out.println(name);
}
String text = "abc";
for (char c : text.toCharArray()) {
System.out.println(c);
}Zu beachten ist, dass String selbst nicht iterierbar ist, aber text.toCharArray() ein Array erzeugt, das es ist.
Eine Map ist ebenfalls nicht direkt Iterable — man iteriert stattdessen über eine ihrer Ansichten: map.keySet(), map.values() oder map.entrySet(). Jede davon gibt ein Set oder eine Collection zurück, die die for-each-Schleife verarbeiten kann.
Die Elementvariable ist eine Kopie
Die Variable im Schleifenkopf erhält den Wert jedes Elements. Bei primitiven Typen ändert eine Modifikation nicht das Array:
int[] nums = {1, 2, 3};
for (int n : nums) {
n *= 10; // doesn't touch nums
}
System.out.println(nums[0]); // still 1Bei Objekten hält die Variable eine Referenz, sodass der Aufruf von Methoden, die das Objekt verändern, das Original beeinflusst. Das Neubelegen der Variable (name = "...";) ändert jedoch nur die lokale Kopie.
Wenn man die Elemente selbst ändern muss, verwendet man eine indizierte Schleife:
for (int i = 0; i < nums.length; i++) {
nums[i] *= 10;
}Wann man for-each nicht verwenden kann
Eine for-each-Schleife versteckt den Index. Das ist der Sinn — bedeutet aber auch, dass man sie nicht verwenden kann, wenn man Folgendes benötigt:
- Den Index (
"item " + i + ": " + value) - Elemente zu entfernen während der Iteration (expliziten
Iteratorverwenden unditerator.remove()aufrufen) - Zwei Collections gleichzeitig (Indizes verwenden)
- Rückwärts zu iterieren oder Elemente zu überspringen (indiziertes
forverwenden)
Collection nicht während der Iteration verändern
Eine for-each-Schleife über eine Collection verwendet intern einen Iterator. Wenn man die Struktur der Collection während der Iteration ändert (Elemente hinzufügt oder entfernt), bemerkt der Iterator die Diskrepanz beim nächsten Schritt und wirft eine ConcurrentModificationException:
List<String> names = new ArrayList<>(List.of("alice", "bob"));
for (String n : names) {
names.remove(n); // ConcurrentModificationException
}Um sicher zu entfernen, steuert man die Schleife mit einem expliziten Iterator und ruft dessen remove() auf — so bleiben Iterator und Liste synchron:
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String n = it.next();
if (n.startsWith("a")) {
it.remove(); // safe
}
}Ab Java 8+ kann man die Schleife oft ganz weglassen: names.removeIf(n -> n.startsWith("a"));.
Ein Element zu lesen oder zu ersetzen (list.set(i, x)) während einer for-each-Schleife ist in Ordnung. Nur strukturelle Änderungen — add und remove an der Collection selbst — lösen die Exception aus.
Ein Praxisbeispiel
Was kommt als Nächstes
Wenn man eine Schleife vorzeitig beenden oder den Rest der aktuellen Iteration überspringen muss, verwendet man break und continue.