1. Background su come sono nati gli iteratori
Hai già familiarità con HashSet
. Se l'hai davvero indagato, oltre a leggere una lezione, allora avresti dovuto porre questa domanda:
Come faccio a visualizzare un elenco di tutti gli elementi HashSet sullo schermo? Dopotutto, l'interfaccia non ha get()
e set()
metodi!
E HashSet
non è solo in questa limitazione. Oltre a HashSet
, esistono molte altre raccolte che non consentono il recupero degli elementi in base all'indice, perché gli elementi non hanno un ordine definito.
Nel corso degli anni, i programmatori hanno inventato molte strutture dati complesse, come grafici e alberi. O liste di liste.
Molti contenitori cambiano l'ordine dei propri elementi quando vengono aggiunti nuovi elementi o vengono rimossi elementi esistenti. Ad esempio, un elenco memorizza gli elementi in un ordine particolare e quando viene aggiunto un nuovo elemento, viene quasi sempre inserito al centro dell'elenco.
E otteniamo anche situazioni in cui è presente un contenitore che memorizza elementi ma non in un ordine fisso.
Supponiamo ora di voler copiare tutti gli elementi da una tale raccolta in un array o in un elenco. Dobbiamo ottenere tutti gli elementi. Non ci interessa l'ordine in cui iteriamo sugli elementi: l'importante è non iterare sugli stessi elementi più di una volta. Come lo facciamo?
2. Iteratore per una raccolta
Gli iteratori sono stati proposti come soluzione al problema di cui sopra.
Un iteratore è un oggetto speciale associato a una raccolta, che consente di attraversare tutti gli elementi della raccolta senza ripeterne nessuno.
È possibile utilizzare il seguente codice per ottenere un iteratore per qualsiasi raccolta:
Iterator<Type> it = name.iterator();
Dove name
è il nome della variabile della raccolta, Type
è il tipo degli elementi della raccolta, iterator()
è uno dei metodi della raccolta ed it
è il nome della variabile iteratore.
Un oggetto iteratore ha 3 metodi:
Metodo | Descrizione |
---|---|
|
Restituisce l'elemento successivo nella raccolta |
|
Controlla se ci sono elementi che non sono stati ancora attraversati |
|
Rimuove l'elemento corrente della raccolta |
nextInt)
Questi metodi sono in qualche modo simili ai metodi e alla classe Scanner hasNextInt()
.
Il next()
metodo restituisce l'elemento successivo della raccolta da cui abbiamo ottenuto l'iteratore.
Il hasNext()
metodo controlla se la raccolta ha elementi aggiuntivi che l'iteratore non ha ancora restituito.
Ecco come visualizzare tutti gli elementi di un HashSet
:
Codice | Appunti |
---|---|
|
Creare un HashSet oggetto che memorizzi String elementi. Aggiungiamo saluti in varie lingue alla set variabile. Ottieni un oggetto iteratore per il set set. Finché ci sono ancora elementi Ottieni l'elemento successivo Visualizza l'elemento sullo schermo |
3. For-each
ciclo
Il principale svantaggio di un iteratore è che il tuo codice diventa più ingombrante rispetto all'utilizzo di un for
ciclo.
Per confrontare, visualizziamo un elenco usando un for
ciclo e anche usando un iteratore:
Iteratore | per ciclo |
---|---|
|
|
Sì, è molto meglio attraversare gli elementi di un ArrayList
usando un loop: tutto risulta essere più breve.
Ma i creatori di Java hanno nuovamente deciso di versarci un po' di zucchero. Fortunatamente per noi, era lo zucchero sintattico .
Hanno dato a Java un nuovo tipo di ciclo e lo hanno chiamato for-each
ciclo. Ecco come appare in generale:
for(Type name:collection)
Dove collection
è il nome della variabile della raccolta, Type
è il tipo degli elementi nella raccolta ed name
è il nome di una variabile che prende il valore successivo dalla raccolta a ogni iterazione del ciclo.
Questo tipo di ciclo scorre tutti gli elementi di una raccolta utilizzando un iteratore implicito. Ecco come funziona effettivamente:
Per ogni ciclo | Cosa vede il compilatore: Loop con un iteratore |
---|---|
|
|
Quando il compilatore incontra un for-each
ciclo nel codice, lo sostituisce semplicemente con il codice a destra: aggiunge una chiamata per ottenere un iteratore insieme a qualsiasi altra chiamata al metodo mancante.
I programmatori adorano il for-each
ciclo e lo usano quasi sempre quando devono eseguire iterazioni su tutti gli elementi di una raccolta.
Anche l'iterazione su un ArrayList
elenco utilizzando un for-each
ciclo sembra più breve:
Per ogni ciclo | per ciclo |
---|---|
|
|
4. Rimozione di un elemento in un for-each
ciclo
Il for-each
ciclo ha uno svantaggio: non può rimuovere correttamente gli elementi. Se scrivi codice come questo, otterrai un errore.
Codice | Nota |
---|---|
|
L'operazione di rimozione genererà un errore! |
Questo è un codice molto bello e comprensibile, ma non funzionerà.
Non puoi modificare una raccolta mentre la stai attraversando con un iteratore.
Ci sono tre modi per aggirare questa limitazione.
1. Usa un diverso tipo di loop
When traversing an ArrayList collection
, puoi utilizzare un normale ciclo con una i
variabile contatore.
Codice |
---|
|
Tuttavia, questa opzione non è adatta per HashSet
e HashMap
collezioni
2. Utilizzare un iteratore esplicito
È possibile utilizzare un iteratore in modo esplicito e chiamarne il remove()
metodo.
Versione che funziona | Versione che non funziona |
---|---|
|
|
Nota che chiamiamo il remove()
metodo sull'oggetto iteratore! L'iteratore sa che l'elemento è stato rimosso e può gestire correttamente la situazione.
3. Usa una copia della raccolta
Puoi anche creare una copia della raccolta e quindi utilizzare la copia in un for-each
ciclo ed eliminare elementi dalla raccolta originale.
Codice | Nota |
---|---|
|
Creare una copia di una raccolta è semplicissimo Il ciclo utilizza l'iteratore per la copia della raccolta. Gli elementi vengono rimossi dalla list raccolta. |
La raccolta viene copiata piuttosto rapidamente, poiché gli elementi stessi non vengono duplicati. Invece, la nuova raccolta memorizza i riferimenti agli elementi che già esistono nella vecchia raccolta.
GO TO FULL VERSION