1. Bakgrunn om hvordan iteratorer ble til
Du er allerede kjent med HashSet
. Hvis du virkelig har undersøkt det, utover å bare lese en leksjon, burde du ha stilt dette spørsmålet:
Hvordan viser jeg en liste over alle HashSet-elementer på skjermen? Tross alt har ikke grensesnittet get()
og set()
metoder!
Og HashSet
er ikke alene om denne begrensningen. I tillegg til HashSet
, er det mange andre samlinger som ikke tillater at elementer hentes etter indeks, fordi elementene ikke har noen definert rekkefølge.
Gjennom årene har programmerere funnet opp mange komplekse datastrukturer, som grafer og trær. Eller lister med lister.
Mange beholdere endrer rekkefølgen på elementene når nye elementer legges til eller eksisterende elementer fjernes. For eksempel lagrer en liste elementer i en bestemt rekkefølge, og når et nytt element legges til, settes det nesten alltid inn i midten av listen.
Og vi får også situasjoner der det er en container som lagrer elementer, men ikke i noen fast rekkefølge.
La oss nå si at vi ønsker å kopiere alle elementene fra en slik samling til en matrise eller liste. Vi må få med oss alle elementene. Vi bryr oss ikke om rekkefølgen vi itererer over elementene - det viktigste er å ikke iterere over de samme elementene mer enn én gang. Hvordan gjør vi det?
2. Iterator for en samling
Iteratorer ble foreslått som en løsning på problemet ovenfor.
En iterator er et spesielt objekt knyttet til en samling, som hjelper til med å krysse alle elementene i samlingen uten å gjenta noen.
Du kan bruke følgende kode for å få en iterator for enhver samling:
Iterator<Type> it = name.iterator();
Hvor name
er navnet på samlingsvariabelen, Type
er typen av elementene i samlingen, iterator()
er en av samlingens metoder, og it
er navnet på iteratorvariabelen.
Et iteratorobjekt har 3 metoder:
Metode | Beskrivelse |
---|---|
|
Returnerer neste element i samlingen |
|
Sjekker om det er noen elementer som ikke er krysset ennå |
|
Fjerner gjeldende element i samlingen |
Disse metodene ligner noe på Scanner-klassens nextInt)
og hasNextInt()
-metodene.
Metoden next()
returnerer det neste elementet i samlingen som vi fikk iteratoren fra.
Metoden hasNext()
sjekker om samlingen har flere elementer som iteratoren ikke har returnert ennå.
Slik viser du alle elementene i en HashSet
:
Kode | Notater |
---|---|
|
Lag et HashSet objekt som lagrer String elementer. Vi legger til hilsener på forskjellige språk til set variabelen. Få et iteratorobjekt for set settet. Så lenge det fortsatt er elementer Hent neste element Vis elementet på skjermen |
3. For-each
løkke
Den største ulempen med en iterator er at koden din blir mer tungvint enn å bruke en for
loop.
For å sammenligne, la oss vise en liste ved hjelp av en for
løkke og også ved å bruke en iterator:
Iterator | for løkke |
---|---|
|
|
Ja, det er mye bedre å krysse elementene i en ArrayList
løkke - alt viser seg å være kortere.
Men Javas skapere bestemte seg igjen for å helle litt sukker på oss. Heldigvis for oss var det syntaktisk sukker .
De ga Java en ny type loop og kalte den en for-each
loop. Slik ser det ut generelt:
for(Type name:collection)
Hvor collection
er navnet på samlingsvariabelen, Type
er typen av elementene i samlingen, og name
er navnet på en variabel som tar neste verdi fra samlingen ved hver iterasjon av løkken.
Denne typen loop itererer gjennom alle elementene i en samling ved å bruke en implisitt iterator. Dette er hvordan det faktisk fungerer:
For hver løkke | Hva kompilatoren ser: Loop med en iterator |
---|---|
|
|
Når kompilatoren møter en for-each
løkke i koden din, erstatter den den ganske enkelt med koden til høyre: den legger til et kall for å få en iterator sammen med eventuelle andre manglende metodekall.
Programmerere elsker for-each
loopen og bruker den nesten alltid når de trenger å iterere over alle elementene i en samling.
Selv å iterere over en ArrayList
liste ved hjelp av en for-each
loop ser kortere ut:
For hver løkke | for løkke |
---|---|
|
|
4. Fjerne et element i en for-each
løkke
Løkken for-each
har en ulempe: den kan ikke fjerne elementer på riktig måte. Hvis du skriver kode som dette, får du en feilmelding.
Kode | Merk |
---|---|
|
Fjernoperasjonen vil generere en feil! |
Dette er en veldig fin og forståelig kode, men den vil ikke fungere.
Du kan ikke endre en samling mens du går gjennom den med en iterator.
Det er tre måter å omgå denne begrensningen på.
1. Bruk en annen type løkke
When traversing an ArrayList collection
, kan du bruke en vanlig sløyfe med en i
tellervariabel.
Kode |
---|
|
Imidlertid er dette alternativet ikke egnet for HashSet
og HashMap
samlinger
2. Bruk en eksplisitt iterator
Du kan bruke en iterator eksplisitt og kalle dens remove()
metode.
Versjon som fungerer | Versjon som ikke fungerer |
---|---|
|
|
Merk at vi kaller remove()
metoden på iteratorobjektet! Iteratoren er klar over at varen er fjernet og kan håndtere situasjonen riktig.
3. Bruk en kopi av samlingen
Du kan også lage en kopi av samlingen og deretter bruke kopien i en for-each
loop og slette elementer fra den originale samlingen.
Kode | Merk |
---|---|
|
Å lage en kopi av en samling er superenkelt. Lokken bruker iteratoren for kopien av samlingen. Elementer fjernes fra list samlingen. |
Samlingen kopieres ganske raskt, siden selve elementene ikke er duplisert. I stedet lagrer den nye kolleksjonen referanser til elementene som allerede finnes i den gamle kolleksjonen.
GO TO FULL VERSION