Jetzt anmelden...

Login
Passwort
Registrieren
25.05.21 110 Views Kommentare [0] 1 0

credit: ©Mike Mareen (Tesla Cybertruck)

Java Tutorial #49

Java Iterator

Der Iterator ist ein generisches Interface, mit dem alle Elemente einer Sammlung sequenziell durchlaufen werden können. Der Iterator steht allen Sammlungsklassen der Java-API zur Verfügung. Wie genau der Iterator funktioniert, zeigen wir dir hier.

Download als eBook

Schnelles Code-Beispiel

Iterator<Elementtyp> it = sammlung.iterator();
while(it.hasNext()){
    Elementtyp e = it.next();
    if(e.getValue() < 10) {
        it.remove();
    }
}

    Inhaltsverzeichnis

  1. Was ist ein Iterator?
  2. Wie funktioniert der Iterator?
  3. Vorteile des Iterators
  4. Übungen

Was ist ein Iterator?

Das Durchlaufen der einzelnen Elemente einer Sammlung ("iterieren") gehört zu den Kernaufgaben im Umgang mit Datenstrukturen. Um diesen Job zu erledigen, stehen uns verschiedene Schleifentypen zur Verfügung.

In Java gibt es neben den Schleifen noch eine weitere Art, die Elemente einer Sammlung zu durchlaufen: Der Iterator.

Der Iterator ist ein generisches Interface, das es mit speziellen Methoden ermöglicht, alle Elemente einer Sammlung sequenziell zu durchlaufen. Der Iterator steht allen Sammlungsklassen der Java-API zur Verfügung.

Wie genau der Iterator funktioniert, zeigen wir dir jetzt.

Wie funktioniert der Iterator?

Das Iterator-Interface befindet sich im Paket java.util und muss entsprechend importiert werden:

import java.util.Iterator;

Bevor wir eine Sammlung mit einem Iterator durchlaufen können, müssen wir zuerst ein Iterator-Objekt erhalten. Hierzu besitzt jede Collection-Klasse eine spezielle Methode namens iterator(), die ein zur Sammlung passendes Iterator-Objekt zurückliefert:

Iterator<Film> it = sammlung.iterator();

In diesem Beispiel erhalten wir einen Iterator für eine Sammlung von Film-Objekten. Der Iterator ist ein generischer Typ und sein jeweiliger Typ-Parameter muss vom gleichen Typ sein wie bei der Sammlung, die wir mit ihm durchlaufen wollen.

Auf dem Iterator-Objekt stehen dann folgende Methoden bereit:

Methoden Iterator
boolean hasNext() Prüft, ob es ein nächstes Element gibt
void next() liefert das nächste Element zurück
remove() Löscht das aktuelle Element

Das "Durchiterieren" der Sammlung läuft so ab:

Iterator<Film> it = sammlung.iterator();
while(it.hasNext()){
    Film f = it.next();
    System.out.println(f.getName());
}

Erklärung: Die Methode hasNext() prüft, ob es ein jeweils nächstes Element in der Sammlung gibt. Falls ja, wird true zurückgeliefert. Innerhalb der Schleife wird mit next() das nächste Element dann zurückgeliefert. Der Pointer wandert danach eine Position auf das nächste Objekt. Mit dieser Technik arbeiten wir uns Element für Element durch die gesamte Sammlung.

Die Infografik illustriert diesen Vorgang:

Java Iterator Infografik

Elemente löschen

Zum Löschen von Elementen während der Iteration kommt die Methode remove() zum Einsatz:

Angenommen, wird möchten alle Filme aus der Sammlung entfernen, die vor dem Jahr 2000 datiert sind, dann können wir das so erledigen:

Iterator<Film> it = sammlung.iterator();
while(it.hasNext()){
    Film f = it.next();
    if(f.getDatum() < 2000) {
        it.remove();
    }
}

Vorteile des Iterators

Wieso brauchen wir zum Löschen während des Durchlaufens der Sammlung extra einen Iterator? Können wir das nicht auch mit den hergebrachten Schleifenkonstruktionen durchführen? Immerhin verfügen die Sammlungsklassen eine eigene remove()-Methode.

Gehen wir der Sache auf den Grund.

Löschen in einer foreach-Schleife

Versuchen wir, Elemente einer Sammlung innerhalb einer foreach-Schleife zu löschen, erhalten als Resultat eine ConcurrentModificationException:

for(Film sV : sammlung) {
    if(sV.getDatum() < 2000){
        sammlung.remove(sV); // ConcurrentModificationException
    }
}

Es ist also nicht möglich, Elemente einer Sammlung während des Durchlaufens mit einer foreach-Schleife zu löschen.

Löschen in einer for-Schleife

Und wie sieht es mit einer index-gesteuerten for-Schleife aus? Technisch gesehen würde das Löschen von Elementen funktionieren, doch sollten wir es trotzdem sein lassen. Entfernt man nämlich Elemente einer Sammlung, ändern sich damit auch die Indizes. So kann es schnell passieren, dass wir eine Schleife programmieren, die nach Manipulation an der zugrunde liegenden Sammlung mit falschen Indizes arbeitet.

Außerdem wird natürlich die Größe der Sammlung nach einem Löschvorgang reduziert, was Einfluss auf die Schleifensteuerrung hat. Hier ein Beispiel:

LinkedList<String> x = new LinkedList<>();
x.add("Phobos");
x.add("Deimos");

for(int i = 0; i < x.size(); i++){
    if(x.get(i).endsWith("s")) {
        x.remove(i);
    }
}
System.out.println(x); // [Deimos]

Hier wollen wir alle String-Elemente löschen, die mit einem "s" enden. Das sollten "Phobos" und "Deimos" sein. Es wird aber nur "Phobos" gelöscht. Der Grund: Nachdem "Phobos" gelöscht wurde, veringert sicht die Größe der Sammlung auf 1. Da die Schleifenvariable nach dem ersten Durchgang ebenfalls 1 ist, ist die Schleifenbedingung nicht mehr erfüllt (1 < 1) und wir kommen nicht mehr an das Element "Deimos" ran.

Stellen wir den Code mit einem Iterator um, funktioniert unser Vorhaben perfekt und es werden beide Elemente der Sammlung gelöscht:

Iterator<String> it = x.iterator();
while(it.hasNext()){
   String s = it.next();
   if(s.endsWith("s")){
       it.remove();
   }
}
System.out.println(x); // []

Fazit

Fassen wir die Unterschiede zwischen Schleifen und dem Iterator also zusammen:

Iterations-Typ Elemente löschen Einsatz
foreach-Schleife nein bei allen Sammlungen
for-Schleife möglich, aber nicht empfohlen nur bei index-gesteuerte Sammlungen
Iterator ja bei allen Sammlungen

Übungen

einfach

Vervollständige den Code, um das "B" aus der Sammlung zu entfernen. Nutze den Iterator!

ArrayList<String> liste = new ArrayList<>();
liste.add("A");
liste.add("B");
liste.add("C");
Lösung ein-/ausblenden

mittel

Was wird mit diesem Code auf der Konsole ausgegeben?

ArrayDeque<Integer> numbers = new ArrayDeque<>();
numbers.push(1);
numbers.push(2);
numbers.push(3);

Iterato<Integer> it = numbers.iterator();
while(it.hasNext()){
     System.out.println(it);
}

A. 123
B. 321
C. nichts
D. 1 in Endlosschleife
E. java.util.ArrayDeque$DeqIterator@60e53b93 in Endlosschleife

Lösung ein-/ausblenden

Falconbyte unterstützen

Kommentar schreiben

Alle Kommentare

Es gibt bislang noch keine Kommentare zu diesem Thema.

Methoden in Java

Wie erstelle ich Methoden?

Verzweigungen in Java

Eine zentrale Notwendigkeit der Programmierung sind Verzweigungen.

switch/ case Anweisung

Benötigen wir eine Unterscheidung nach vielen Fällen empfehlen sich switch-case-Statements.

FALCONBYTE.NET

Handmade with 🖤️

© 2018-2021 Stefan E. Heller

Impressum | Datenschutz

facebook programmieren lernen twitter programmieren lernen discord programmieren lernen