1. Baggrund for, hvordan iteratorer blev til
Du er allerede bekendt med HashSet
. Hvis du virkelig har undersøgt det, ud over blot at læse en lektion, så skulle du have stillet dette spørgsmål:
Hvordan viser jeg en liste over alle HashSet-elementer på skærmen? Efter alt, har grænsefladen ikke get()
og set()
metoder!
Og HashSet
er ikke alene om denne begrænsning. Ud over HashSet
, er der mange andre samlinger, der ikke tillader elementer at blive hentet efter indeks, fordi elementerne ikke har nogen defineret rækkefølge.
Gennem årene har programmører opfundet masser af komplekse datastrukturer, såsom grafer og træer. Eller lister med lister.
Mange containere ændrer rækkefølgen af deres elementer, når nye elementer tilføjes eller eksisterende elementer fjernes. For eksempel gemmer en liste elementer i en bestemt rækkefølge, og når et nyt element tilføjes, indsættes det næsten altid i midten af listen.
Og vi får også situationer, hvor der er en container, der opbevarer elementer, men ikke i nogen fast rækkefølge.
Lad os nu sige, at vi vil kopiere alle elementer fra en sådan samling til en matrix eller liste. Vi skal have alle elementerne med. Vi er ligeglade med den rækkefølge, vi itererer over elementerne i - det vigtige er ikke at iterere over de samme elementer mere end én gang. Hvordan gør vi det?
2. Iterator til en samling
Iteratorer blev foreslået som en løsning på problemet ovenfor.
En iterator er et særligt objekt forbundet med en samling, som hjælper med at krydse alle elementer i samlingen uden at gentage nogen.
Du kan bruge følgende kode til at få en iterator til enhver samling:
Iterator<Type> it = name.iterator();
Hvor name
er navnet på samlingsvariablen, Type
er typen af elementerne i samlingen, iterator()
er en af samlingens metoder og it
er navnet på iteratorvariablen.
Et iteratorobjekt har 3 metoder:
Metode | Beskrivelse |
---|---|
|
Returnerer det næste element i samlingen |
|
Kontrollerer, om der er elementer, der ikke er gennemløbet endnu |
|
Fjerner det aktuelle element i samlingen |
Disse metoder minder lidt om Scanner-klassens nextInt)
og hasNextInt()
-metoderne.
Metoden next()
returnerer det næste element i samlingen, hvorfra vi fik iteratoren.
Metoden hasNext()
kontrollerer, om samlingen har yderligere elementer, som iteratoren ikke har returneret endnu.
Sådan viser du alle elementerne i en HashSet
:
Kode | Noter |
---|---|
|
Opret et HashSet objekt, der gemmer String elementer. Vi tilføjer hilsner på forskellige sprog til variablen set . Få et iteratorobjekt til sættet set . Så længe der stadig er elementer Hent det næste element Vis elementet på skærmen |
3. For-each
sløjfe
Den største ulempe ved en iterator er, at din kode bliver mere besværlig end at bruge en for
loop.
For at sammenligne, lad os vise en liste ved hjælp af en for
loop og også ved hjælp af en iterator:
Iterator | for sløjfe |
---|---|
|
|
Ja, det er meget bedre at krydse elementerne i en ArrayList
løkke - alt viser sig at være kortere.
Men Javas skabere besluttede igen at hælde noget sukker på os. Heldigvis for os var det syntaktisk sukker .
De gav Java en ny slags loop og kaldte det en for-each
loop. Sådan ser det generelt ud:
for(Type name:collection)
Hvor collection
er navnet på samlingsvariablen, Type
er typen af elementerne i samlingen og name
er navnet på en variabel, der tager den næste værdi fra samlingen ved hver iteration af løkken.
Denne form for sløjfe gentager alle elementerne i en samling ved hjælp af en implicit iterator. Sådan fungerer det faktisk:
For hver sløjfe | Hvad compileren ser: Loop med en iterator |
---|---|
|
|
Når compileren støder på en for-each
løkke i din kode, erstatter den den blot med koden til højre: den tilføjer et kald for at få en iterator sammen med eventuelle andre manglende metodekald.
Programmører elsker for-each
løkken og bruger den næsten altid, når de skal gentage alle elementerne i en samling.
Selv iteration over en ArrayList
liste ved hjælp af en for-each
loop ser kortere ud:
For hver sløjfe | for sløjfe |
---|---|
|
|
4. Fjernelse af et element i en for-each
løkke
Sløjfen for-each
har én ulempe: den kan ikke fjerne elementer korrekt. Hvis du skriver kode som denne, får du en fejl.
Kode | Bemærk |
---|---|
|
Fjernelse vil generere en fejl! |
Dette er en meget flot og forståelig kode, men den virker ikke.
Du kan ikke ændre en samling, mens du krydser den med en iterator.
Der er tre måder at omgå denne begrænsning på.
1. Brug en anden slags løkke
When traversing an ArrayList collection
, kan du bruge en almindelig sløjfe med en i
tællervariabel.
Kode |
---|
|
Denne mulighed er dog ikke egnet til HashSet
og HashMap
samlinger
2. Brug en eksplicit iterator
Du kan bruge en iterator eksplicit og kalde dens remove()
metode.
Version der virker | En version der ikke virker |
---|---|
|
|
Bemærk, at vi kalder remove()
metoden på iteratorobjektet! Iteratoren er klar over, at varen er blevet fjernet og kan håndtere situationen korrekt.
3. Brug en kopi af samlingen
Du kan også oprette en kopi af samlingen og derefter bruge kopien i en for-each
løkke og slette elementer fra den originale samling.
Kode | Bemærk |
---|---|
|
Det er super nemt at oprette en kopi af en samling. Sløjfen bruger iteratoren til kopien af samlingen. Elementer fjernes fra list samlingen. |
Samlingen kopieres ret hurtigt, da selve elementerne ikke er duplikeret. I stedet gemmer den nye kollektion referencer til de elementer, der allerede findes i den gamle kollektion.
GO TO FULL VERSION