"Ciao, Amico!"

"Ciao, Eli!"

"Oggi voglio parlarvi degli iteratori."

"Gli iteratori sono stati inventati praticamente contemporaneamente alle raccolte. Lo scopo principale delle raccolte è memorizzare elementi e lo scopo principale di un iteratore è recuperare questi elementi uno per uno."

"Cosa c'è di così difficile nell'ottenere un insieme di elementi?"

"In primo luogo, gli elementi in alcune raccolte, come Set, non hanno un ordine stabilito e/o l'ordine cambia costantemente."

"In secondo luogo, alcune strutture di dati possono memorizzare oggetti in un modo molto complesso: in diversi gruppi, elenchi, ecc. In altre parole, distribuire tutti gli elementi in ordine sarebbe un compito non banale."

"In terzo luogo, le raccolte tendono a cambiare. Supponi di decidere di visualizzare l'intero contenuto di una raccolta, ma proprio nel mezzo dell'output la JVM passa a un altro thread che sostituisce metà degli elementi della raccolta. Quindi, invece dell'output, ottieni chissà cosa».

"Hmm..."

"Ma! Questi sono precisamente il tipo di problemi che un iteratore può risolvere. Un iteratore è un oggetto speciale all'interno di una raccolta che, da un lato, ha accesso a tutti i suoi dati privati ​​e ne conosce la struttura interna, e dall'altro , implementa l'interfaccia pubblica di Iterator, che consente a tutti di sapere come utilizzarla. "

"Alcuni iteratori hanno un array interno in cui vengono copiati tutti gli elementi della raccolta quando viene creato l'iteratore. Ciò garantisce che eventuali modifiche successive alla raccolta non influenzino il numero o l'ordine degli elementi."

"Penso che tu ti sia imbattuto in questo quando lavori con for each . Non puoi scorrere contemporaneamente una raccolta e rimuovere elementi da essa. Questo è tutto proprio a causa del modo in cui funziona un iteratore."

"Nelle nuove raccolte aggiunte alla libreria di concorrenza, l'iteratore viene rielaborato per eliminare questo problema."

"Lascia che ti ricordi come funziona un iteratore."

"Java ha un'interfaccia Iterator speciale. Ecco i suoi metodi:"

Metodi dell'interfaccia Iterator<E> Descrizione
boolean hasNext() Controlla se ci sono altri elementi
E next() Restituisce l'elemento corrente e passa al successivo.
void remove() Rimuove l'elemento corrente

"Un iteratore ti consente di ottenere successivamente tutti gli elementi di una raccolta. È più logico pensare a un iteratore come qualcosa di simile a un InputStream: ha tutti i dati, ma il suo compito è di emetterli in sequenza."

"Il   metodo next () restituisce l'elemento successivo nella raccolta."

"Il metodo hasNext () viene utilizzato per verificare se ci sono altri elementi."

"E remove () rimuove l'elemento corrente."

"Qualsiasi domanda?"

"Perché i metodi hanno nomi così strani? Perché non isEmpty() e getNextElement()?"

"Non avrebbe più senso?"

"Avrebbe più senso, ma i nomi derivano dal linguaggio C++, dove gli iteratori apparivano prima."

"Capisco. Continuiamo."

"Oltre a un iteratore, esiste anche l'interfaccia Iterable, che deve essere implementata da tutte le raccolte che supportano gli iteratori. Ha un unico metodo:"

Metodi dell'interfaccia Iterable<T> Descrizione
Iterator<T>iterator() Restituisce un oggetto iteratore

"Puoi usare questo metodo su qualsiasi raccolta per fare in modo che un oggetto iteratore passi attraverso i suoi elementi. Esaminiamo tutti gli elementi di in un TreeSet :"

Esempio
TreeSet<String> set = new TreeSet<String>();
Iterator<String> iterator = set.iterator();

while (iterator.hasNext())
{
 String item = iterator.next();
 System.out.println(item);
}

"Utilizzare un iteratore come questo non è molto conveniente: c'è troppo codice superfluo e ovvio. La situazione è diventata più semplice quando il ciclo for-each è apparso in Java."

"Ora questo codice è molto più compatto e leggibile:"

Prima Dopo
TreeSet<String> set = new TreeSet<String>();
Iterator<String> iterator = set.iterator();

while (iterator.hasNext())
{
 String item = iterator.next();
 System.out.println(item);
}
TreeSet<String> set = new TreeSet<String>();

for(String item : set)
{
 System.out.println(item);
}

"Questo è lo stesso codice! L'iteratore è usato in entrambi i casi."

"È solo che il suo utilizzo è nascosto nel ciclo for-each . Nota che il codice a destra non ha alcun testo rosso . L'uso dell'iteratore è completamente nascosto."

"Un ciclo for-each può essere utilizzato per tutti gli oggetti che supportano gli iteratori. In altre parole, puoi scrivere la tua classe, aggiungervi il metodo iterator () e utilizzare i suoi oggetti in un costrutto for-each ."

"Wow! Certo, non sono ansioso di scrivere le mie raccolte e i miei iteratori, ma la prospettiva è ancora allettante. Ne prenderò nota."

Inoltre, c'è un altro popolare tipo di iteratore che ha anche una propria interfaccia. Sto parlando di un iteratore per le liste, cioè ListIterator .

"Indipendentemente dalla loro implementazione, le liste mantengono l'ordine degli elementi, il che rende un po' più conveniente lavorare con esse tramite un iteratore."

"Ecco i metodi dell'interfaccia ListIterator <E>:"

Metodo Descrizione
boolean hasNext() Controlla se ci sono altri elementi avanti.
E next() Restituisce l'elemento successivo.
int nextIndex() Restituisce l'indice dell'elemento successivo
void set(E e) Modifica il valore dell'elemento corrente
boolean hasPrevious() Controlla se ci sono elementi dietro.
E previous() Restituisce l'elemento precedente
int previousIndex() Restituisce l'indice dell'elemento precedente
void remove() Rimuove l'elemento corrente
void add(E e) Aggiunge un elemento alla fine dell'elenco.

"In altre parole, qui possiamo muoverci sia avanti che indietro. E ci sono un paio di altre piccole caratteristiche."

"Beh, questa è roba interessante. Dove viene usata?"

"Supponiamo che tu voglia spostarti avanti e indietro su un elenco collegato. L'operazione get sarà piuttosto lenta, ma l'operazione next() sarà molto veloce."

"Hmm. Mi hai convinto. Lo terrò a mente."

"Grazie, Eli!"