1. Az iterátorok létrejöttének háttere

Ön már ismeri a HashSet. Ha valóban megvizsgáltad, nem csak egy leckét olvastál, akkor fel kellett volna tenned ezt a kérdést:

Hogyan jeleníthetem meg az összes HashSet elem listáját a képernyőn? Hiszen a felületnek nincsenek get()és set()metódusai!

És HashSetnincs egyedül ezzel a korláttal. A mellett HashSetsok más gyűjtemény is nem teszi lehetővé az elemek index szerinti lekérését, mert az elemeknek nincs meghatározott sorrendje.

Az évek során a programozók rengeteg összetett adatstruktúrát, például grafikonokat és fákat találtak ki. Vagy listák listái.

Sok tároló megváltoztatja az elemek sorrendjét, amikor új elemeket adnak hozzá vagy a meglévő elemeket eltávolítják. Például egy lista meghatározott sorrendben tárolja az elemeket, és új elem hozzáadásakor az szinte mindig a lista közepére kerül.

És kapunk olyan helyzeteket is, amikor van egy konténer, amely ugyan tárolja az elemeket, de nem fix sorrendben.

Tegyük fel, hogy egy ilyen gyűjtemény összes elemét egy tömbbe vagy listába szeretnénk másolni. Minden elemet meg kell szereznünk. Nem törődünk azzal, hogy milyen sorrendben iteráljuk az elemeket – az a fontos, hogy ne ismételjük ugyanazokat az elemeket többször. Hogyan csináljuk?


2. Iterátor egy gyűjteményhez

A fenti probléma megoldásaként iterátorokat javasoltak.

Az iterátor egy gyűjteményhez társított speciális objektum, amely segít a gyűjtemény összes elemén áthaladni anélkül, hogy megismételné azokat.

A következő kóddal bármilyen gyűjteményhez beszerezhet iterátort:

Iterator<Type> it = name.iterator();

Hol nametalálható a gyűjteményváltozó neve, Typea gyűjtemény elemeinek típusa, iterator()a gyűjtemény egyik metódusa, és itaz iterátor változó neve.

Egy iterátor objektumnak 3 metódusa van:

Módszer Leírás
Type next()
A gyűjtemény következő elemét adja vissza
boolean hasNext()
Ellenőrzi, hogy vannak-e még nem bejárt elemek
void remove()
Eltávolítja a gyűjtemény aktuális elemét

Ezek a metódusok némileg hasonlóak a Scanner osztályhoz nextInt)és hasNextInt()metódusokhoz.

A next()metódus a gyűjtemény következő elemét adja vissza, amelyből az iterátort kaptuk.

A hasNext()metódus ellenőrzi, hogy a gyűjteményben vannak-e olyan további elemek, amelyeket az iterátor még nem adott vissza.

A következőképpen jelenítheti meg az összes elemet HashSet:

Kód Megjegyzések
HashSet<String> set = new HashSet<String>();

set.add("Hallo");
set.add("Hello");
set.add("Hola");
set.add("Bonjour");
set.add("Ciao");
set.add("Namaste");

Iterator<String> it = set.iterator();
while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}
Hozzon létre egy HashSetobjektumot, amely elemeket tárol String.


A változóhoz különféle nyelvű üdvözletet adunk set.




Szerezzen be egy iterátor objektumot a halmazhoz set.
Amíg vannak még elemek

A következő elem lekérése
Jelenítse meg az elemet a képernyőn


3. For-eachhurok

Az iterátor fő hátránya, hogy a kód nehezebbé válik, mint a forciklus használata.

Az összehasonlításhoz jelenítsen meg egy listát egy forciklus és egy iterátor segítségével:

Iterátor hurokhoz
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);
}

Igen, sokkal jobb egy ciklus elemeit bejárni ArrayList– minden rövidebbnek bizonyul.

De a Java alkotói ismét úgy döntöttek, hogy ránk öntenek egy kis cukrot. Szerencsére a szintaktikai cukor volt .

Adtak egy újfajta ciklust a Java-nak, és ciklusnak nevezték el for-each. Így néz ki általánosságban:

for(Type name:collection)

Hol collectiontalálható a gyűjteményváltozó neve, Typea gyűjtemény elemeinek típusa, és nameegy olyan változó neve, amely a ciklus minden iterációja során a következő értéket veszi fel a gyűjteményből.

Ez a fajta ciklus egy implicit iterátor segítségével iterál a gyűjtemény összes elemén. Valójában így működik:

Minden hurokhoz Amit a fordító lát: ciklus iterátorral
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);
}

Amikor a fordító for-eachciklust talál a kódban, egyszerűen lecseréli azt a jobb oldali kódra: hozzáad egy hívást, hogy iterátort kapjon a többi hiányzó metódushívás mellett.

A programozók szeretik a for-eachciklust, és szinte mindig használják, amikor egy gyűjtemény összes elemén át kell ismételni.

Még a ArrayListlista for-eachcikluson keresztüli iterációja is rövidebbnek tűnik:

Minden hurokhoz hurokhoz
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. Elem eltávolítása a for-eachhurokban

A for-eachhuroknak van egy hátránya: nem tudja megfelelően eltávolítani az elemeket. Ha ilyen kódot ír, hibaüzenetet kap.

Kód jegyzet
ArrayList<String> list = new ArrayList<String>();

list.add("Hallo");
list.add("Hello");
list.add("Hola");
list.add("Bonjour");
list.add("Ciao");
list.add("Namaste");

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












Az eltávolítási művelet hibát generál!

Ez egy nagyon szép és érthető kód, de nem fog működni.

Fontos!

Nem módosíthatja a gyűjteményt, miközben iterátorral járja be.

Háromféleképpen lehet megkerülni ezt a korlátozást.

1. Használjon másfajta hurkot

When traversing an ArrayList collection, használhat egy közönséges ciklust számlálóváltozóval i.

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

   if (str.equals("Hello"))
   {
      list.remove(str);
      i--; // We need to decrease i, because the remove operation shifted the elements
   }
}

Ez a lehetőség azonban nem alkalmas HashSetgyűjteményekhezHashMap

2. Használjon explicit iterátort

Használhat egy iterátort kifejezetten, és meghívhatja a metódusát remove().

Működő verzió Nem működő verzió
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); }

remove()Jegyezzük meg, hogy a metódust az iterátor objektumon hívjuk meg ! Az iterátor tudatában van annak, hogy az elemet eltávolították, és megfelelően tudja kezelni a helyzetet.

3. Használja a gyűjtemény másolatát

Létrehozhat egy másolatot a gyűjteményről, majd a másolatot ciklusban használhatja, for-eachés törölhet elemeket az eredeti gyűjteményből.

Kód jegyzet
ArrayList<String> listCopy = new ArrayList(list);

for (String str: listCopy)
{
   if (str.equals("Hello"))
      list.remove(str);
}
A gyűjtemény másolatának létrehozása rendkívül egyszerű



A ciklus az iterátort használja a gyűjtemény másolatához.
Az elemek eltávolításra kerülnek a gyűjteményből list.

A gyűjteményt meglehetősen gyorsan másolják, mivel maguk az elemek nem duplikálódnak. Ehelyett az új gyűjtemény hivatkozásokat tárol a régi gyűjteményben már meglévő elemekre.