Java Language
Iteratore e Iterable
Ricerca…
introduzione
java.util.Iterator
è l'interfaccia standard Java SE per oggetti che implementano il modello di progettazione Iterator. L'interfaccia java.lang.Iterable
è per gli oggetti che possono fornire un iteratore.
Osservazioni
È possibile iterare su un array usando il ciclo for
-each, sebbene gli array java non implementino Iterable; l'iterazione viene eseguita da JVM utilizzando un indice non accessibile in background.
Uso di loop Iterable in for
Le classi che implementano l'interfaccia Iterable<>
possono essere utilizzate in cicli for
. Questo è in realtà solo zucchero sintattico per ottenere un iteratore dall'oggetto e utilizzarlo per ottenere tutti gli elementi in sequenza; rende il codice più chiaro, più veloce da scrivere e meno incline agli errori.
public class UsingIterable {
public static void main(String[] args) {
List<Integer> intList = Arrays.asList(1,2,3,4,5,6,7);
// List extends Collection, Collection extends Iterable
Iterable<Integer> iterable = intList;
// foreach-like loop
for (Integer i: iterable) {
System.out.println(i);
}
// pre java 5 way of iterating loops
for(Iterator<Integer> i = iterable.iterator(); i.hasNext(); ) {
Integer item = i.next();
System.out.println(item);
}
}
}
Utilizzando l'iteratore raw
L'uso del ciclo foreach (o "extended for loop") è semplice, a volte è utile utilizzare direttamente l'iteratore. Ad esempio, se desideri generare un gruppo di valori separati da virgola, ma non vuoi che l'ultimo elemento abbia una virgola:
List<String> yourData = //...
Iterator<String> iterator = yourData.iterator();
while (iterator.hasNext()){
// next() "moves" the iterator to the next entry and returns it's value.
String entry = iterator.next();
System.out.print(entry);
if (iterator.hasNext()){
// If the iterator has another element after the current one:
System.out.print(",");
}
}
Questo è molto più facile e più chiaro di avere una variabile isLastEntry
o fare calcoli con l'indice di loop.
Crea il tuo Iterable.
Per creare il tuo Iterable come con qualsiasi interfaccia, devi semplicemente implementare i metodi astratti nell'interfaccia. Per Iterable
c'è solo uno che è chiamato iterator()
. Ma il suo tipo di ritorno Iterator
è di per sé un'interfaccia con tre metodi astratti. Puoi restituire un iteratore associato ad alcune raccolte o creare la tua implementazione personalizzata:
public static class Alphabet implements Iterable<Character> {
@Override
public Iterator<Character> iterator() {
return new Iterator<Character>() {
char letter = 'a';
@Override
public boolean hasNext() {
return letter <= 'z';
}
@Override
public Character next() {
return letter++;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Doesn't make sense to remove a letter");
}
};
}
}
Usare:
public static void main(String[] args) {
for(char c : new Alphabet()) {
System.out.println("c = " + c);
}
}
Il nuovo Iterator
dovrebbe avere uno stato che punta al primo elemento, ogni chiamata al successivo aggiorna il suo stato in modo che punti a quello successivo. hasNext()
controlla se l'iteratore è alla fine. Se l'iteratore fosse collegato a una raccolta modificabile, il metodo remove()
facoltativo dell'iteratore potrebbe essere implementato per rimuovere l'elemento attualmente indirizzato dalla raccolta sottostante.
Rimozione di elementi mediante un iteratore
Il metodo Iterator.remove()
è un metodo facoltativo che rimuove l'elemento restituito dalla precedente chiamata a Iterator.next()
. Ad esempio, il codice seguente popola un elenco di stringhe e quindi rimuove tutte le stringhe vuote.
List<String> names = new ArrayList<>();
names.add("name 1");
names.add("name 2");
names.add("");
names.add("name 3");
names.add("");
System.out.println("Old Size : " + names.size());
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String el = it.next();
if (el.equals("")) {
it.remove();
}
}
System.out.println("New Size : " + names.size());
Produzione :
Old Size : 5
New Size : 3
Nota che il codice sopra è il modo sicuro per rimuovere elementi mentre si itera una raccolta tipica. Se invece, provi a rimuovere elementi da una raccolta come questa:
for (String el: names) {
if (el.equals("")) {
names.remove(el); // WRONG!
}
}
una raccolta tipica (come ArrayList
) che fornisce agli iteratori la semantica dell'iteratore di fail veloce genererà una ConcurrentModificationException
.
Il metodo remove()
può solo chiamare (una volta) dopo una chiamata next()
. Se viene chiamato prima di chiamare next()
o se viene chiamato due volte dopo una chiamata next()
, allora la chiamata remove()
genererà un IllegalStateException
.
L'operazione di remove
è descritta come un'operazione opzionale ; cioè non tutti gli iteratori lo permetteranno. Esempi in cui non è supportato includono iteratori per raccolte immutabili, viste di sola lettura di raccolte o raccolte di dimensioni fisse. Se remove()
viene chiamato quando l'iteratore non supporta la rimozione, genererà un UnsupportedOperationException
.