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 HashSeter 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 nameer navnet på samlingsvariabelen, Typeer typen av elementene i samlingen, iterator()er en av samlingens metoder, og iter 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 HashSetobjekt som lagrer Stringelementer. Vi legger til hilsener på forskjellige språk til setvariabelen. Få et iteratorobjekt for setsettet. Så lenge det fortsatt er elementer Hent neste element Vis elementet på skjermen |
3. For-eachløkke
Den største ulempen med en iterator er at koden din blir mer tungvint enn å bruke en forloop.
For å sammenligne, la oss vise en liste ved hjelp av en forløkke og også ved å bruke en iterator:
| Iterator | for løkke |
|---|---|
|
|
Ja, det er mye bedre å krysse elementene i en ArrayListlø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-eachloop. Slik ser det ut generelt:
for(Type name:collection)
Hvor collectioner navnet på samlingsvariabelen, Typeer typen av elementene i samlingen, og nameer 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-eachlø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-eachloopen og bruker den nesten alltid når de trenger å iterere over alle elementene i en samling.
Selv å iterere over en ArrayListliste ved hjelp av en for-eachloop ser kortere ut:
| For hver løkke | for løkke |
|---|---|
|
|
4. Fjerne et element i en for-eachløkke
Løkken for-eachhar 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 itellervariabel.
| Kode |
|---|
|
Imidlertid er dette alternativet ikke egnet for HashSetog HashMapsamlinger
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-eachloop 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 listsamlingen. |
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