Java Language
Iterator und Iterable
Suche…
Einführung
java.util.Iterator
ist die Standard-Java SE-Schnittstelle für Objekte, die das Iterator-Entwurfsmuster implementieren. Die Schnittstelle java.lang.Iterable
ist für Objekte java.lang.Iterable
, die einen Iterator bereitstellen können.
Bemerkungen
Es ist möglich, ein Array mithilfe der for
-each-Schleife for
durchlaufen, obwohl Java-Arrays keine Iterable-Funktion implementieren. Das Iterieren wird von JVM mit einem nicht zugänglichen Index im Hintergrund ausgeführt.
Iterable in for-Schleife verwenden
Klassen, die die Iterable<>
-Schnittstelle implementieren, können in for
Schleifen verwendet werden. Dies ist eigentlich nur syntaktischer Zucker , um einen Iterator vom Objekt zu erhalten und ihn zu verwenden, um alle Elemente nacheinander zu erhalten. Es macht den Code klarer, schneller zu schreiben und weniger fehleranfällig.
public class UsingIterable {
public static void main(String[] args) {
List<Integer> intList = Arrays.asList(1,2,3,4,5,6,7);
// List extends Collection, Collection extends Iterable
Iterable<Integer> iterable = intList;
// foreach-like loop
for (Integer i: iterable) {
System.out.println(i);
}
// pre java 5 way of iterating loops
for(Iterator<Integer> i = iterable.iterator(); i.hasNext(); ) {
Integer item = i.next();
System.out.println(item);
}
}
}
Verwenden des rohen Iterators
Während die Verwendung der foreach-Schleife (oder "extended for loop") einfach ist, ist es manchmal von Vorteil, den Iterator direkt zu verwenden. Wenn Sie beispielsweise eine Reihe von durch Kommas getrennten Werten ausgeben möchten, das letzte Element jedoch kein Komma enthalten soll:
List<String> yourData = //...
Iterator<String> iterator = yourData.iterator();
while (iterator.hasNext()){
// next() "moves" the iterator to the next entry and returns it's value.
String entry = iterator.next();
System.out.print(entry);
if (iterator.hasNext()){
// If the iterator has another element after the current one:
System.out.print(",");
}
}
Dies ist viel einfacher und übersichtlicher als eine isLastEntry
Variable oder Berechnungen mit dem Schleifenindex.
Erstellen Sie Ihre eigenen Iterable.
Um Ihre eigene Iterable wie mit jeder Schnittstelle zu erstellen, implementieren Sie einfach die abstrakten Methoden in der Schnittstelle. Für Iterable
gibt es nur einen, der iterator()
. Der Iterator
Rückgabetyp ist selbst eine Schnittstelle mit drei abstrakten Methoden. Sie können einen mit einer Sammlung verknüpften Iterator zurückgeben oder Ihre eigene benutzerdefinierte Implementierung erstellen:
public static class Alphabet implements Iterable<Character> {
@Override
public Iterator<Character> iterator() {
return new Iterator<Character>() {
char letter = 'a';
@Override
public boolean hasNext() {
return letter <= 'z';
}
@Override
public Character next() {
return letter++;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Doesn't make sense to remove a letter");
}
};
}
}
Benutzen:
public static void main(String[] args) {
for(char c : new Alphabet()) {
System.out.println("c = " + c);
}
}
Der neue Iterator
sollte einen Status aufweisen, der auf das erste Element verweist. Jeder Aufruf von next aktualisiert seinen Status so, dass er auf das nächste Element verweist. Das hasNext()
prüft, ob der Iterator am Ende ist. Wenn der Iterator mit einer modifizierbaren Auflistung verbunden war, könnte die optionale remove()
Methode des Iterators implementiert werden, um das aktuell aufgerufene Element aus der zugrunde liegenden Auflistung zu entfernen.
Elemente mit einem Iterator entfernen
Die Iterator.remove()
-Methode ist eine optionale Methode, die das vom vorherigen Aufruf von Iterator.next()
Element entfernt. Mit dem folgenden Code wird beispielsweise eine Liste von Zeichenfolgen aufgefüllt und anschließend alle leeren Zeichenfolgen entfernt.
List<String> names = new ArrayList<>();
names.add("name 1");
names.add("name 2");
names.add("");
names.add("name 3");
names.add("");
System.out.println("Old Size : " + names.size());
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String el = it.next();
if (el.equals("")) {
it.remove();
}
}
System.out.println("New Size : " + names.size());
Ausgabe :
Old Size : 5
New Size : 3
Beachten Sie, dass der obige Code der sichere Weg ist, Elemente zu entfernen, während Sie eine typische Sammlung durchlaufen. Wenn Sie stattdessen versuchen, Elemente aus einer Sammlung wie folgt zu entfernen:
for (String el: names) {
if (el.equals("")) {
names.remove(el); // WRONG!
}
}
Eine typische Auflistung (z. B. ArrayList
), die Iteratoren mit Fail-Fast- Iteratorsemantik bereitstellt, löst eine ConcurrentModificationException
.
Die remove()
Methode kann nur (einmal) nach einem next()
Aufruf aufgerufen werden. Wenn es vor dem Aufruf von next()
aufgerufen wird oder zweimal nach einem next()
Aufruf aufgerufen wird, IllegalStateException
der remove()
Aufruf eine IllegalStateException
.
Der Vorgang zum remove
wird als optionaler Vorgang beschrieben. dh nicht alle Iteratoren werden es zulassen. Beispiele, bei denen dies nicht unterstützt wird, sind Iteratoren für unveränderliche Sammlungen, schreibgeschützte Ansichten von Sammlungen oder Sammlungen mit fester Größe. Wenn remove()
aufgerufen wird, wenn der Iterator das Entfernen nicht unterstützt, wird eine UnsupportedOperationException
.