1. Bakgrund om hur iteratorer kom till
Du är redan bekant med HashSet
. Om du verkligen har undersökt det, utöver att bara läsa en lektion, borde du ha ställt den här frågan:
Hur visar jag en lista över alla HashSet-element på skärmen? När allt kommer omkring, har gränssnittet inte get()
och set()
metoder!
Och HashSet
är inte ensam om denna begränsning. Förutom , HashSet
finns det många andra samlingar som inte tillåter att element hämtas med index, eftersom elementen inte har någon definierad ordning.
Genom åren har programmerare uppfunnit massor av komplexa datastrukturer, som grafer och träd. Eller listor med listor.
Många behållare ändrar ordningen på sina element när nya element läggs till eller befintliga element tas bort. Till exempel lagrar en lista element i en viss ordning, och när ett nytt element läggs till infogas det nästan alltid i mitten av listan.
Och vi får även situationer där det finns en container som lagrar element men inte i någon fast ordning.
Låt oss nu säga att vi vill kopiera alla element från en sådan samling till en array eller lista. Vi måste få med oss alla element. Vi bryr oss inte om i vilken ordning vi itererar över elementen - det viktiga är att inte iterera över samma element mer än en gång. Hur gör vi det?
2. Iterator för en samling
Iteratorer föreslogs som en lösning på problemet ovan.
En iterator är ett speciellt objekt som är associerat med en samling, som hjälper till att passera alla element i samlingen utan att upprepa några.
Du kan använda följande kod för att få en iterator för alla samlingar:
Iterator<Type> it = name.iterator();
Var name
är namnet på samlingsvariabeln, Type
är typen av element i samlingen, iterator()
är en av samlingens metoder och it
är namnet på iteratorvariabeln.
Ett iteratorobjekt har tre metoder:
Metod | Beskrivning |
---|---|
|
Returnerar nästa element i samlingen |
|
Kontrollerar om det finns några element som inte har passerats ännu |
|
Tar bort det aktuella elementet i samlingen |
Dessa metoder liknar i viss mån Scanner-klassens nextInt)
och hasNextInt()
metoderna.
Metoden next()
returnerar nästa element i samlingen som vi fick iteratorn från.
Metoden hasNext()
kontrollerar om samlingen har ytterligare element som iteratorn inte har returnerat ännu.
Så här visar du alla element i en HashSet
:
Koda | Anteckningar |
---|---|
|
Skapa ett HashSet objekt som lagrar String element. Vi lägger till hälsningar på olika språk till set variabeln. Skaffa ett iteratorobjekt för uppsättningen set . Så länge det fortfarande finns element Hämta nästa element Visa elementet på skärmen |
3. For-each
slinga
Den största nackdelen med en iterator är att din kod blir mer krånglig än att använda en for
loop.
För att jämföra, låt oss visa en lista med en for
loop och även med en iterator:
Iterator | för slinga |
---|---|
|
|
Ja, det är mycket bättre att gå igenom elementen i ArrayList
en loop - allt visar sig vara kortare.
Men Javas skapare bestämde sig återigen för att hälla lite socker på oss. Lyckligtvis för oss var det syntaktisk socker .
De gav Java en ny typ av loop och kallade den en for-each
loop. Så här ser det ut i allmänhet:
for(Type name:collection)
Var collection
är namnet på samlingsvariabeln, Type
är typen av element i samlingen och name
är namnet på en variabel som tar nästa värde från samlingen vid varje iteration av loopen.
Denna typ av loop itererar genom alla element i en samling med hjälp av en implicit iterator. Så här fungerar det faktiskt:
För varje slinga | Vad kompilatorn ser: Slinga med en iterator |
---|---|
|
|
När kompilatorn stöter på en for-each
loop i din kod, ersätter den den helt enkelt med koden till höger: den lägger till ett anrop för att få en iterator tillsammans med eventuella andra saknade metodanrop.
Programmerare älskar for-each
loopen och använder den nästan alltid när de behöver iterera över alla delar av en samling.
Även att iterera över en ArrayList
lista med en for-each
loop ser kortare ut:
För varje slinga | för slinga |
---|---|
|
|
4. Ta bort ett element i en for-each
slinga
Slingan for-each
har en nackdel: den kan inte ta bort element korrekt. Om du skriver kod så här får du ett felmeddelande.
Koda | Notera |
---|---|
|
Ta bort operationen kommer att generera ett fel! |
Detta är en mycket trevlig och begriplig kod, men den kommer inte att fungera.
Du kan inte ändra en samling medan du går igenom den med en iterator.
Det finns tre sätt att komma runt denna begränsning.
1. Använd en annan typ av slinga
When traversing an ArrayList collection
, kan du använda en vanlig slinga med en i
räknarvariabel.
Koda |
---|
|
Det här alternativet är dock inte lämpligt för HashSet
och HashMap
samlingar
2. Använd en explicit iterator
Du kan använda en iterator explicit och anropa dess remove()
metod.
Version som fungerar | En version som inte fungerar |
---|---|
|
|
Observera att vi anropar remove()
metoden på iteratorobjektet! Iteratorn är medveten om att föremålet har tagits bort och kan hantera situationen korrekt.
3. Använd en kopia av samlingen
Du kan också skapa en kopia av samlingen och sedan använda kopian i en for-each
slinga och ta bort element från originalsamlingen.
Koda | Notera |
---|---|
|
Att skapa en kopia av en samling är superenkelt. Slingan använder iteratorn för kopian av samlingen. Element tas bort från list samlingen. |
Samlingen kopieras ganska snabbt, eftersom själva elementen inte är duplicerade. Den nya kollektionen lagrar istället referenser till de element som redan finns i den gamla kollektionen.