Zuletzt aktualisiert am 16.12.2025 5 Minuten Lesezeit

Iterator

Ein Iterator ist ein Entwurfsmuster und Programmierkonstrukt, das den sequenziellen Zugriff auf Elemente einer Sammlung (z.B. Liste, Array, Set) ermöglicht, ohne die interne Struktur der Sammlung offenzulegen. Der Iterator kapselt den Traversierungsmechanismus in einem separaten Objekt und stellt eine einheitliche Schnittstelle zum Durchlaufen von Datenstrukturen bereit.

In praktisch allen modernen Programmiersprachen spielen Iteratoren eine zentrale Rolle – sie bilden die Grundlage für foreach-Schleifen und ermöglichen die elegante Verarbeitung von Datensammlungen.

Grundprinzip des Iterators

Das Iterator-Pattern gehört zu den Verhaltensmustern (Behavioral Design Patterns) der objektorientierten Programmierung. Es löst das Problem, wie man auf Elemente einer Sammlung zugreifen kann, ohne deren interne Struktur zu kennen oder zu verändern.

Ein Iterator bietet typischerweise zwei Kernfunktionen:

  • Prüfen, ob weitere Elemente existieren (z.B. hasNext() in Java)
  • Abrufen des nächsten Elements (z.B. next())

Eine hilfreiche Analogie: Stell dir einen Iterator wie ein Lesezeichen in einem Buch vor. Das Buch (die Sammlung) enthält alle Seiten, aber das Lesezeichen (der Iterator) markiert, wo du gerade bist und ermöglicht dir, zur nächsten Seite zu blättern.

Iterator vs. Iterable

Ein häufiger Stolperstein für Einsteiger ist der Unterschied zwischen Iterator und Iterable. Diese beiden Konzepte arbeiten zusammen, haben aber unterschiedliche Aufgaben:

Konzept Beschreibung Typische Methoden
Iterable Ein Objekt, das eine Sammlung repräsentiert und einen Iterator erzeugen kann iterator() (Java), __iter__() (Python)
Iterator Ein Objekt, das den aktuellen Traversierungszustand verwaltet und Elemente liefert next(), hasNext()

Eine Liste ist iterable – sie kann einen Iterator erzeugen. Der Iterator selbst ist das Werkzeug, das durch die Liste wandert. Du kannst mehrere Iteratoren für dieselbe Sammlung erstellen, die unabhängig voneinander arbeiten.

Codebeispiele in verschiedenen Sprachen

Das Iterator-Konzept findet sich in allen gängigen Programmiersprachen, wobei die Syntax variiert.

Java

import java.util.List;
import java.util.Iterator;

List<String> sprachen = List.of("Java", "Python", "JavaScript");
Iterator<String> iterator = sprachen.iterator();

while (iterator.hasNext()) {
    String sprache = iterator.next();
    System.out.println(sprache);
}

// Oder kürzer mit foreach:
for (String sprache : sprachen) {
    System.out.println(sprache);
}

Python

sprachen = ["Java", "Python", "JavaScript"]
iterator = iter(sprachen)

print(next(iterator))  # Java
print(next(iterator))  # Python
print(next(iterator))  # JavaScript

# Oder einfacher mit for-Schleife:
for sprache in sprachen:
    print(sprache)

JavaScript

const sprachen = ["Java", "Python", "JavaScript"];
const iterator = sprachen[Symbol.iterator]();

console.log(iterator.next().value);  // Java
console.log(iterator.next().value);  // Python
console.log(iterator.next().value);  // JavaScript

// Oder mit for...of:
for (const sprache of sprachen) {
    console.log(sprache);
}

C#

string[] sprachen = { "Java", "Python", "JavaScript" };
IEnumerator<string> enumerator = ((IEnumerable<string>)sprachen).GetEnumerator();

while (enumerator.MoveNext())
{
    Console.WriteLine(enumerator.Current);
}

// Oder mit foreach:
foreach (string sprache in sprachen)
{
    Console.WriteLine(sprache);
}

Foreach-Schleifen und Iteratoren

Die foreach-Schleife (auch enhanced for loop oder for-in/for-of) ist syntaktischer Zucker, der intern einen Iterator verwendet. Wenn du schreibst:

for (String element : liste) {
    System.out.println(element);
}

Wird vom Compiler intern ungefähr folgender Code erzeugt:

Iterator<String> iter = liste.iterator();
while (iter.hasNext()) {
    String element = iter.next();
    System.out.println(element);
}

Das Verständnis dieser Verbindung hilft dir zu verstehen, warum bestimmte Operationen (wie das Entfernen von Elementen während der Iteration) Probleme verursachen können.

Vorteile des Iterator-Patterns

Das Iterator-Pattern bietet mehrere wichtige Vorteile für die Softwareentwicklung:

  • Entkopplung: Der Client-Code muss die interne Struktur der Sammlung nicht kennen. Eine LinkedList, ein Array oder ein Baum – alle können mit demselben Iterator-Interface durchlaufen werden.
  • Einheitliche Schnittstelle: Unterschiedliche Datenstrukturen bieten dieselbe Traversierungs-API, was den Code austauschbar und testbar macht.
  • Mehrere Traversierungen: Du kannst mehrere Iteratoren gleichzeitig auf derselben Sammlung verwenden, die unabhängig voneinander arbeiten.
  • Lazy Evaluation: Iteratoren können Elemente erst bei Bedarf berechnen, was bei großen Datenmengen Speicher spart.
  • Flexibilität: Verschiedene Traversierungsalgorithmen (vorwärts, rückwärts, gefiltert) können als separate Iterator-Implementierungen bereitgestellt werden.

Eigene Iteratoren implementieren

In manchen Situationen musst du eigene Iteratoren für benutzerdefinierte Datenstrukturen implementieren. Hier ein einfaches Beispiel in Java:

import java.util.Iterator;

public class Zahlenbereich implements Iterable<Integer> {
    private int start;
    private int ende;

    public Zahlenbereich(int start, int ende) {
        this.start = start;
        this.ende = ende;
    }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            private int aktuell = start;

            @Override
            public boolean hasNext() {
                return aktuell <= ende;
            }

            @Override
            public Integer next() {
                return aktuell++;
            }
        };
    }
}

// Verwendung:
for (int zahl : new Zahlenbereich(1, 5)) {
    System.out.println(zahl);  // Gibt 1, 2, 3, 4, 5 aus
}

Praktische Anwendungsfälle

Iteratoren begegnen dir in der Praxis häufig:

  • Datenbankabfragen: ResultSets in JDBC verwenden Iteratoren, um Ergebnisse zeilenweise zu verarbeiten, ohne alle Daten auf einmal in den Speicher zu laden.
  • Dateiverarbeitung: Zeilen einer Textdatei können iterativ gelesen werden.
  • Stream-Verarbeitung: Java Streams, Python Generators und LINQ in C# basieren auf Iterator-Konzepten.
  • UI-Komponenten: Durchlaufen von Elementen in Listen, Tabellen oder Baumstrukturen.
  • Paginierung: APIs liefern Ergebnisse seitenweise, wobei jede Seite iteriert werden kann.

Häufige Fehler vermeiden

Beim Arbeiten mit Iteratoren gibt es typische Fallstricke:

  • ConcurrentModificationException: Wenn du während der Iteration Elemente aus der Sammlung entfernst, wirft Java eine Exception. Nutze stattdessen iterator.remove() oder arbeite mit einer Kopie.
  • Iterator erschöpft: Ein Iterator kann nur einmal durchlaufen werden. Nach dem letzten Element musst du einen neuen Iterator erstellen.
  • NoSuchElementException: Rufe next() nur auf, wenn hasNext() true zurückgibt, sonst erhältst du eine Exception.
  • Zustandsbehaftet: Iteratoren speichern ihre Position. Wenn du einen Iterator an eine Methode übergibst, kann diese den Zustand verändern.

Iterator in der IT-Ausbildung

Das Verständnis von Iteratoren ist grundlegend für die Ausbildung zum Fachinformatiker für Anwendungsentwicklung. Iteratoren gehören zu den Design Patterns, die in der Prüfung und im Berufsalltag relevant sind. Sie bilden die Basis für das Arbeiten mit Collections und Datenstrukturen in allen gängigen Programmiersprachen.

Verwandte Konzepte

  • Design Patterns: Iterator ist eines der 23 klassischen GoF-Patterns
  • Kapselung: Iteratoren kapseln den Traversierungsmechanismus
  • Generatoren: In Python und JavaScript eine spezielle Form von Iteratoren mit yield
  • Streams: Moderne Erweiterung des Iterator-Konzepts für funktionale Programmierung

Quellen und weiterführende Links