Thema in Kurzform
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.
// Code in Kurzform
Iterator<Elementtyp> it = sammlung.iterator();
while(it.hasNext()){
Elementtyp e = it.next();
if(e.getValue() < 10) {
it.remove();
}
}
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.
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 zeigt diesen Vorgang:
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();
}
}
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.
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.
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]
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 |
Java Basics
[Java einrichten] [Variablen] [Primitive Datentypen] [Operatoren] [if else] [switch-case] [Arrays] [Schleifen]
Objektorientierung
[Einstieg] [Variablen ] [Konstruktor] [Methoden] [Rekursion] [Statische Member] [Initializer] [Pass-by-value] [Objektsammlungen] [Objektinteraktion] [Objekte löschen]
Klassenbibliothek
[Allgemeines] [String ] [Math] [Wrapper] [Scanner] [java.util.Arrays] [Date-Time-API]
Vererbung
[Einstieg Vererbung] [Konstruktoren bei Vererbung ] [Der protected Zugriffsmodifikator] [Abstrakte Klassen und Methoden] [Polymorphie in Java] [Typumwandlung] [Die Klasse Object] [Die toString()-Methode] [Objekte vergleichen] [Was ist ein Interface?]