Wie for-each in Java funktioniert: Analyse anhand von Beispielen vom Anfänger bis zum Profi

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum for-each zum "König" der Schleifen in Java wurde?

\n\n

Wenn Sie auch nur eine Woche Java geschrieben haben, sind Sie bestimmt schon auf die Konstruktion for (Type var : collection) gestoßen. Diese prägnante Syntax wird als for-each-Schleife (oder enhanced for loop) bezeichnet. Sie wurde bereits in Java 5 (2004) eingeführt und schnell zum Liebling der Entwickler.

\n\n

Aber wissen Sie, was unter der Haube passiert, wenn die JVM auf diese Konstruktion trifft? Warum kann for-each für Arrays langsamer sein als ein normales for? Und warum wirft es manchmal ConcurrentModificationException, selbst wenn Sie nichts löschen?

\n\n

In diesem Artikel analysieren wir wie for-each in Java funktioniert auf Bytecode-Ebene, vergleichen es mit klassischen Schleifen und lernen, typische Fallstricke zu vermeiden. Los geht's!

\n\n

Syntax und erste Bekanntschaft

\n\n

Die grundlegende Syntax sieht so aus:

\n\n
for (ElementTyp variable : sammlung_oder_array) {\n    // Schleifenkörper\n}
\n\n

Ein Beispiel mit ArrayList:

\n\n
List<String> names = Arrays.asList("Anna", "Boris", "Viktor");\n\nfor (String name : names) {\n    System.out.println("Hallo, " + name + "!");\n}
\n\n

Ausgabe:

\n\n
Hallo, Anna!\nHallo, Boris!\nHallo, Viktor!
\n\n

Ganz einfach? Ja. Aber hinter dieser Einfachheit verbergen sich zwei völlig unterschiedliche Mechanismen – für Arrays und für Sammlungen.

\n\n

Wie funktioniert for-each mit Arrays?

\n\n

Wenn Sie for-each für ein Array schreiben, wandelt der Java-Compiler es in ein normales for mit Index um. Keine Magie.

\n\n

Ihr Code:

\n\n
int[] numbers = {10, 20, 30};\n\nfor (int num : numbers) {\n    System.out.println(num);\n}
\n\n

Nach der Kompilierung (dekompilieren Sie den Bytecode – überzeugen Sie sich selbst):

\n\n
int[] numbers = new int[]{10, 20, 30};\nfor (int i = 0; i < numbers.length; i++) {\n    int num = numbers[i];\n    System.out.println(num);\n}
\n\n

Wichtige Schlussfolgerung: Für Arrays sind for-each und normales for in Bezug auf die Leistung identisch. Keine zusätzlichen Kosten für Iteratoren.

\n\n

Wie funktioniert for-each mit Sammlungen (List, Set)?

\n\n

Und hier wird es richtig interessant. Für Sammlungen verwendet for-each einen Iterator.

\n\n

Ihr Code:

\n\n
List<String> list = new ArrayList<>();\nlist.add("Java");\nlist.add("Python");\nlist.add("C++");\n\nfor (String lang : list) {\n    System.out.println(lang);\n}
\n\n

Der Compiler wandelt dies um in:

\n\n
List<String> list = new ArrayList<>();\nlist.add("Java");\nlist.add("Python");\nlist.add("C++");\n\nfor (Iterator<String> it = list.iterator(); it.hasNext(); ) {\n    String lang = it.next();\n    System.out.println(lang);\n}
\n\n

Das heißt:

\n
    \n
  • list.iterator() wird aufgerufen – wir erhalten einen Iterator.
  • \n
  • In der Bedingung steht it.hasNext().
  • \n
  • Im Schleifenkörper steht it.next().
  • \n
  • Die Variable lang wird mit dem Ergebnis von next() initialisiert.
  • \n
\n\n

Was bedeutet das in der Praxis?

\n
    \n
  • Elemente können nicht gelöscht werden innerhalb von for-each über list.remove() – Sie erhalten eine ConcurrentModificationException. Verwenden Sie it.remove() oder ein normales for.
  • \n
  • Die Sammlung darf nicht geändert werden (hinzufügen/löschen) während der Iteration – derselbe Fehler.
  • \n
  • Leistung: Für ArrayList ist der Unterschied zu einem normalen for minimal (Erstellung des Iterator-Objekts). Für LinkedList ist for-each viel schneller als for (int i = 0; i < list.size(); i++), da get(i) bei LinkedList jedes Mal O(n) ist!
  • \n
\n\n

Was ist mit Map? Iteration über Schlüssel-Wert-Paare

\n\n

Map implementiert Iterable nicht direkt, daher for-each

Blogs

Buchempfehlungen