1. Historia pojawienia się iteratora

Poznałeś już wielu HashSet. A jeśli naprawdę się tym zajmowałeś, a nie tylko wykładałeś, powinieneś był się zastanawiać:

A jak wyświetlić listę wszystkich elementów zestawu HashSet na ekranie? get()W końcu na wielu nie ma metod set()!

I HashSetnie jest sam w swoim problemie. Oprócz HashSet, istnieje wiele innych kolekcji, dla których nie można uzyskać elementu po numerze, ponieważ nie ma jasnej kolejności elementów.

Programiści wymyślili kiedyś wiele złożonych struktur danych, takich jak wykres, drzewo. Lub na przykład lista list.

Wiele kontenerów zmienia kolejność swoich elementów po dodaniu nowych elementów lub usunięciu istniejących elementów. Na przykład istnieje lista, która przechowuje elementy w posortowanej kolejności, a kiedy dodawany jest nowy element, prawie zawsze jest on wstawiany na środku listy.

Otrzymujemy więc sytuację, że istnieje kontener zawierający elementy, same elementy również istnieją, ale nie ma ustalonej kolejności.

Ale powiedzmy, że chcemy skopiować wszystkie elementy z takiej kolekcji do tablicy lub listy. Musimy zdobyć wszystkie elementy. Nie dbamy o to, w jakiej kolejności je obchodzimy, najważniejsze, aby się nie powtarzać. Jak możemy to zrobić?


2. Iterator kolekcji

Jako rozwiązanie powyższego problemu zaproponowano rozwiązanie - iterator .

Iterator to specjalny obiekt kolekcji, który pomaga iterować po wszystkich elementach kolekcji i nie powtarzać się.

Możesz uzyskać iterator z dowolnej kolekcji za pomocą kodu:

Iterator<Тип> it = Nazwa.iterator();

Gdzie Nazwato nazwa zmiennej kolekcji, Типto typ elementów kolekcji. iterator()jest metodą zbierania. itjest nazwą zmiennej obiektowej iteratora.

Obiekt iteratora ma 3 metody:

metoda Opis
Тип next()
Zwraca następny element kolekcji
boolean hasNext()
Sprawdza, czy istnieją elementy, które nie zostały jeszcze przekazane
void remove()
Usuwa bieżący element kolekcji

Te metody są nieco podobne do metod klasy Scanner: nextInt()i hasNextInt().

Metoda next()zwraca kolejny element kolekcji, z której otrzymaliśmy iterator.

Metoda hasNext()sprawdza, czy w kolekcji jest więcej elementów, których iterator nie zwrócił.

Oto jak możesz wyświetlić wszystkie elementy zestawu HashSet:

Kod Notatki
HashSet<String> set = new HashSet<String>();

set.add("Cześć");
set.add("Hello");
set.add("Hola");
set.add("Bonjour");
set.add("Cialo");
set.add("Namaste");

Iterator<String> it = set.iterator();
while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}
Tworzymy obiekt typu HashSet, który przechowuje elementy typu String.


Dodajemy setpozdrowienia w różnych językach.




Otrzymujemy obiekt iteratora ze zbioru set.
Dopóki są jeszcze elementy

Zdobądź następny element
Wyświetl element na ekranie


3. Pętlafor-each

Główną wadą iteratora jest to, że używanie go do kodu jest jeszcze bardziej kłopotliwe niż użycie pętli for.

Wyświetlmy listę za pomocą pętli fori iteratora dla porównania:

iterator dla pętli
ArrayList<String> list = new ArrayList<String>();

Iterator<String> it = list.iterator();
while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();

for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);
   System.out.println(str);
}

Tak, ArrayListdużo lepiej jest poruszać się po elementach listy za pomocą pętli - wszystko jest krótsze.

Jednak programiści Javy postanowili znowu dać nam cukier. I na szczęście dla nas znowu był to cukier składniowy .

Dodali nowy rodzaj pętli do Javy i nazwali ją for-each. Oto jak to ogólnie wygląda:

for(Тип Nazwa:коллекция)

Gdzie коллекцияjest nazwą zmiennej kolekcji, Типjest typem elementów kolekcji i Nazwajest nazwą zmiennej, która pobiera następną wartość z kolekcji w każdej iteracji pętli.

Ta pętla przechodzi przez wszystkie elementy kolekcji za pomocą ukrytego iteratora. Oto jak to faktycznie działa:

dla każdej pętli Co widzi kompilator: Pętla iteratora
ArrayList<String> list = new ArrayList<String>();

for (String str: list)
{
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();
Iterator<String> it = list.iterator();

while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}

Gdy kompilator napotka pętlę w twoim kodzie for-each, po prostu zastąpi ją kodem po prawej stronie: doda gettera iteratora i wszelkie brakujące wywołania metod.

Programiści bardzo lubią pętle for-eachi prawie zawsze używają ich, gdy muszą przejrzeć wszystkie elementy kolekcji.

Nawet przeglądanie listy ArrayListza pomocą pętli for-eachwygląda krócej:

dla każdej pętli dla pętli
ArrayList<String> list = new ArrayList<String>();

for (String str: list)
{
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();

for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);
   System.out.println(str);
}


4. Usuwanie elementu w pętlifor-each

Cykl for-eachma jeden minus: nie wie, jak poprawnie usunąć elementy. Jeśli napiszesz taki kod, pojawi się błąd.

Kod Notatka
ArrayList<String> list = new ArrayList<String>();

list.add("Cześć");
list.add("Hello");
list.add("Hola");
list.add("Bonjour");
list.add("Cialo");
list.add("Namaste");

for (String str: list)
{
   if (str.equals("Hello"))
      list.remove(str);
}












Podczas usuwania wystąpi błąd!

To bardzo piękny i zrozumiały kod, ale nie zadziała.

Ważny!

Nie możesz modyfikować kolekcji podczas iteracji za pomocą iteratora.

Istnieją trzy sposoby obejścia tego ograniczenia.

1 Korzystanie z innego cyklu

Jeśli iterujesz nad kolekcją ArrayList, możesz użyć zwykłej pętli licznika i.

Kod
for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);

   if (str.equals("Hello"))
   {
      list.remove(str);
      i--;    // нужно уменьшить i, т.к. после удаления элементы сдвинулись
   }
}

Jednak ta opcja nie jest odpowiednia dla kolekcji HashSetiHashMap

2 Jawne użycie iteratora

Możesz jawnie użyć iteratora i użyć jego remove().

wersja robocza Opcja niedziałająca
Iterator<String> it = set.iterator();
while (it.hasNext())
{
   String str = it.next();
   if (str.equals("Hello"))
       it.remove();
}

for
(String str: list) { if (str.equals("Hello")) list.remove(str); }

Zauważ, że remove()wywołujemy metodę na obiekcie iteratora! Iterator będzie „wiedział”, że element został usunięty i będzie w stanie odpowiednio obsłużyć tę sytuację.

3 Korzystanie z kopii kolekcji

Możesz także utworzyć kopię kolekcji i użyć for-eachkolekcji-kopiowania w pętli oraz usunąć elementy z oryginalnej kolekcji.

Kod Notatka
ArrayList<String> listCopy = new ArrayList(list);

for (String str: listCopy)
{
   if (str.equals("Hello"))
      list.remove(str);
}
Tworzenie kopii kolekcji jest bardzo proste.Pętla



wykorzystuje iterator kolekcji kopii.
Elementy są usuwane z kolekcji list.

Kopia kolekcji tworzona jest dość szybko: elementy nie są duplikowane podczas kopiowania kolekcji, nowa kolekcja będzie zawierała linki do tych samych elementów, co stara.