1. Achtergrondinformatie over hoe iterators zijn ontstaan
Je bent al bekend met HashSet
. Als je het echt hebt onderzocht, afgezien van alleen het lezen van een les, dan had je deze vraag moeten stellen:
Hoe toon ik een lijst met alle HashSet-elementen op het scherm? De interface heeft immers geen get()
en set()
methoden!
En HashSet
is niet de enige in deze beperking. Naast HashSet
, zijn er veel andere collecties die het niet mogelijk maken om elementen op te halen via index, omdat de elementen geen gedefinieerde volgorde hebben.
Door de jaren heen hebben programmeurs veel complexe datastructuren uitgevonden, zoals grafieken en bomen. Of lijsten met lijsten.
Veel containers veranderen de volgorde van hun elementen wanneer nieuwe elementen worden toegevoegd of bestaande elementen worden verwijderd. Een lijst slaat bijvoorbeeld elementen in een bepaalde volgorde op en wanneer een nieuw element wordt toegevoegd, wordt het bijna altijd in het midden van de lijst ingevoegd.
En we krijgen ook situaties waarin er een container is die elementen opslaat, maar niet in een vaste volgorde.
Laten we nu zeggen dat we alle elementen uit zo'n verzameling naar een array of lijst willen kopiëren. We moeten alle elementen krijgen. Het maakt ons niet uit in welke volgorde we de elementen herhalen - het belangrijkste is om dezelfde elementen niet meer dan één keer te herhalen. Hoe doen we dat?
2. Iterator voor een verzameling
Iterators werden voorgesteld als een oplossing voor het bovenstaande probleem.
Een iterator is een speciaal object dat aan een verzameling is gekoppeld en dat helpt alle elementen van de verzameling te doorlopen zonder er een te herhalen.
U kunt de volgende code gebruiken om een iterator voor elke verzameling te krijgen:
Iterator<Type> it = name.iterator();
Waar name
is de naam van de verzamelingsvariabele, Type
is het type elementen van de verzameling, iterator()
is een van de verzamelingsmethoden en it
is de naam van de iteratorvariabele.
Een iterator-object heeft 3 methoden:
Methode | Beschrijving |
---|---|
|
Retourneert het volgende element in de verzameling |
|
Controleert of er elementen zijn die nog niet zijn doorlopen |
|
Verwijdert het huidige element van de collectie |
Deze methoden lijken enigszins op die van de klasse Scanner nextInt)
en hasNextInt()
de methoden.
De next()
methode retourneert het volgende element van de verzameling waaruit we de iterator hebben gehaald.
De hasNext()
methode controleert of de verzameling aanvullende elementen bevat die de iterator nog niet heeft geretourneerd.
Zo kunt u alle elementen van een weergeven HashSet
:
Code | Notities |
---|---|
|
Maak een HashSet object dat String elementen opslaat. We voegen begroetingen in verschillende talen toe aan de set variabele. Verkrijg een iterator-object voor de set set. Zolang er nog elementen zijn Pak het volgende element Toon het element op het scherm |
3. For-each
lus
Het grootste nadeel van een iterator is dat uw code omslachtiger wordt dan het gebruik van een for
lus.
Laten we ter vergelijking een lijst weergeven met een for
lus en ook met een iterator:
Iterator | for loop |
---|---|
|
|
Ja, het is veel beter om de elementen van ArrayList
een lus te doorlopen — alles blijkt korter te zijn.
Maar de makers van Java besloten opnieuw wat suiker over ons heen te gieten. Gelukkig voor ons was het syntactische suiker .
Ze gaven Java een nieuw soort lus en noemden het een for-each
lus. Zo ziet het er in het algemeen uit:
for(Type name:collection)
Waar collection
is de naam van de verzamelingsvariabele, Type
is het type elementen in de verzameling en name
is de naam van een variabele die de volgende waarde uit de verzameling haalt bij elke iteratie van de lus.
Dit soort lus doorloopt alle elementen van een verzameling met behulp van een impliciete iterator. Dit is hoe het echt werkt:
Voor elke lus | Wat de compiler ziet: Lus met een iterator |
---|---|
|
|
Wanneer de compiler een for-each
lus in uw code tegenkomt, vervangt hij deze eenvoudig door de code aan de rechterkant: hij voegt een aanroep toe om een iterator te krijgen, samen met eventuele andere ontbrekende methodeaanroepen.
Programmeurs houden van de for-each
lus en gebruiken deze bijna altijd wanneer ze alle elementen van een verzameling moeten herhalen.
Zelfs het doorlopen van een ArrayList
lijst met een for-each
lus ziet er korter uit:
Voor elke lus | for loop |
---|---|
|
|
for-each
4. Een element in een lus verwijderen
De for-each
lus heeft één nadeel: hij kan elementen niet correct verwijderen. Als je op deze manier code schrijft, krijg je een foutmelding.
Code | Opmerking |
---|---|
|
De verwijderingsbewerking genereert een fout! |
Dit is een erg mooie en begrijpelijke code, maar het zal niet werken.
U kunt een verzameling niet wijzigen terwijl u deze doorloopt met een iterator.
Er zijn drie manieren om deze beperking te omzeilen.
1. Gebruik een ander soort lus
When traversing an ArrayList collection
, kunt u een gewone lus gebruiken met een i
tellervariabele.
Code |
---|
|
Deze optie is echter niet geschikt voor HashSet
en HashMap
collecties
2. Gebruik een expliciete iterator
U kunt expliciet een iterator gebruiken en de remove()
methode ervan aanroepen.
Versie die werkt | Versie die niet werkt |
---|---|
|
|
Merk op dat we de remove()
methode op het iterator-object aanroepen! De iterator is zich ervan bewust dat het item is verwijderd en kan de situatie correct afhandelen.
3. Gebruik een kopie van de collectie
U kunt ook een kopie van de verzameling maken en de kopie vervolgens in een for-each
lus gebruiken en elementen uit de oorspronkelijke verzameling verwijderen.
Code | Opmerking |
---|---|
|
Een kopie van een verzameling maken is supereenvoudig. De lus gebruikt de iterator voor de kopie van de verzameling. Elementen worden uit de collectie verwijderd list . |
De verzameling wordt vrij snel gekopieerd, aangezien de elementen zelf niet worden gedupliceerd. In plaats daarvan slaat de nieuwe collectie verwijzingen op naar de elementen die al in de oude collectie bestaan.
GO TO FULL VERSION