Szukaj…


Wprowadzenie

java.util.Iterator to standardowy interfejs Java SE dla obiektów implementujących wzorzec projektowy Iterator. Interfejs java.lang.Iterable jest przeznaczony dla obiektów, które mogą zapewnić iterator.

Uwagi

Możliwe jest iterowanie po tablicy za pomocą pętli for -each, chociaż tablice java nie implementują Iterable; iteracja jest wykonywana przez JVM przy użyciu niedostępnego indeksu w tle.

Korzystanie z pętli Iterable in for

Ćwiczenia wdrażające Iterable<> interfejs może być używany w for pętli. W rzeczywistości jest to tylko cukier syntaktyczny do pobierania iteratora z obiektu i używania go do sekwencyjnego pobierania wszystkich elementów; sprawia, że kod jest bardziej przejrzysty, szybszy do pisania i mniej podatny na błędy.

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);
        }
    }
}

Korzystanie z surowego iteratora

Podczas gdy korzystanie z pętli foreach (lub „Extended for loop”) jest proste, czasem korzystne jest bezpośrednie użycie iteratora. Na przykład, jeśli chcesz wydzielić kilka wartości oddzielonych przecinkami, ale nie chcesz, aby ostatni element zawierał przecinek:

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(",");
    }
}

Jest to o wiele łatwiejsze i bardziej zrozumiałe niż posiadanie zmiennej isLastEntry lub wykonywanie obliczeń za pomocą indeksu pętli.

Tworzenie własnej iterowalności.

Aby stworzyć własną Iterable jak w każdym interfejsie, wystarczy zaimplementować w interfejsie metody abstrakcyjne. W przypadku Iterable istnieje tylko jeden, który nazywa się iterator() . Jednak jego zwracany typ Iterator jest interfejsem z trzema metodami abstrakcyjnymi. Możesz zwrócić iterator powiązany z niektórymi kolekcjami lub utworzyć własną niestandardową implementację:

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");
            }
        };
    }
}

Używać:

public static void main(String[] args) {
    for(char c : new Alphabet()) {
        System.out.println("c = " + c);
    }
}

Nowy Iterator powinien mieć stan wskazujący na pierwszy element, każde wywołanie next aktualizuje swój stan, wskazując na następny. hasNext() sprawdza, czy iterator jest na końcu. Gdyby iterator był połączony z kolekcją, którą można modyfikować, opcjonalna metoda remove() iteratora mogłaby zostać zaimplementowana w celu usunięcia elementu wskazanego obecnie z kolekcji podstawowej.

Usuwanie elementów za pomocą iteratora

Metoda Iterator.remove() jest opcjonalną metodą, która usuwa element zwrócony przez poprzednie wywołanie Iterator.next() . Na przykład poniższy kod zapełnia listę ciągów, a następnie usuwa wszystkie puste ciągi.

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());

Wynik :

Old Size : 5
New Size : 3

Zauważ, że powyższy kod to bezpieczny sposób usuwania elementów podczas iteracji typowej kolekcji. Jeśli zamiast tego spróbujesz usunąć elementy z takiej kolekcji:

for (String el: names) {
    if (el.equals("")) {
        names.remove(el); // WRONG!
    }
}

typowa kolekcja (taka jak ArrayList ), która udostępnia iteratorom semantykę szybkiego iteratora, zgłosi wyjątek ConcurrentModificationException .

Metoda remove() może być wywołana (tylko raz) po next() wywołaniu next() . Jeśli zostanie wywołane przed wywołaniem next() lub jeśli zostanie wywołane dwukrotnie po wywołaniu next() , wówczas wywołanie remove() spowoduje zgłoszenie IllegalStateException .

Operacja remove jest opisana jako operacja opcjonalna ; tzn. nie wszystkie iteratory na to pozwolą. Przykłady, w których nie jest obsługiwane, to iteratory dla niezmiennych kolekcji, widoki kolekcji tylko do odczytu lub kolekcje o stałym rozmiarze. Jeśli funkcja remove() zostanie wywołana, gdy iterator nie obsługuje usuwania, zgłosi UnsupportedOperationException .



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow