Suche…


Einführung

Der 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 .



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow