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 HashSet
nincs egyedül ezzel a korláttal. A mellett HashSet
sok 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 name
található a gyűjteményváltozó neve, Type
a gyűjtemény elemeinek típusa, iterator()
a gyűjtemény egyik metódusa, és it
az iterátor változó neve.
Egy iterátor objektumnak 3 metódusa van:
Módszer | Leírás |
---|---|
|
A gyűjtemény következő elemét adja vissza |
|
Ellenőrzi, hogy vannak-e még nem bejárt elemek |
|
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 |
---|---|
|
Hozzon létre egy HashSet objektumot, 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-each
hurok
Az iterátor fő hátránya, hogy a kód nehezebbé válik, mint a for
ciklus használata.
Az összehasonlításhoz jelenítsen meg egy listát egy for
ciklus és egy iterátor segítségével:
Iterátor | hurokhoz |
---|---|
|
|
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 collection
található a gyűjteményváltozó neve, Type
a gyűjtemény elemeinek típusa, és name
egy 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 |
---|---|
|
|
Amikor a fordító for-each
ciklust 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-each
ciklust, és szinte mindig használják, amikor egy gyűjtemény összes elemén át kell ismételni.
Még a ArrayList
lista for-each
cikluson keresztüli iterációja is rövidebbnek tűnik:
Minden hurokhoz | hurokhoz |
---|---|
|
|
4. Elem eltávolítása a for-each
hurokban
A for-each
huroknak 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 |
---|---|
|
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.
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 |
---|
|
Ez a lehetőség azonban nem alkalmas HashSet
gyű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ó |
---|---|
|
|
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 |
---|---|
|
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.
GO TO FULL VERSION