È possibile iterare esternamente ad una collezione attraverso:

  • l’oggetto iterator della collezione
  • il costrutto for each
  • indici se si utilizzano liste liste

È possibile iterare internamente ad una collezione attraverso attraverso:

  • il metodo forEach(Consumer<?> action)
  • funzioni degli Java - Streams come forEach, map, filter

Iterator

Per tutte le strutture dati che estendono Collection (e che quindi estendono Iterable) è possibile utilizzare l’oggetto iterator per iterare sulla collezione.

ArrayList`<Persona> persone = new ArrayList<>();  
persone.add(new Persona("Mario", "Rossi"));  
persone.add(new Persona("Luca", "Bianchi"));  
 
Iterator`<Persona> iteratore = persone.iterator();  
System.out.println(iteratore.next());   // print Mario Rossi  
System.out.println(iteratore.next());   // print Luca Bianchi

Nota non è possibile utilizzare questo metodo su le mappe perché non estendono iterable.

Costrutto For Each

Il costrutto for each in Java è un modo sintattico per iterare su una collezione, ma in realtà, il compilatore Java lo traduce in un ciclo for tradizionale che utilizza un oggetto Iterator per iterare sulla collezione.

for (Persona persona : persone) { 
  System.out.println(persona); 
}

Le mappe in Java non implementano l’interfaccia Iterable e quindi non è possibile utilizzare il costrutto for each direttamente su di esse.

Tuttavia è possibile utilizzare il costrutto for each sul set delle chiavi della mappa (che si può ottenere con il metodo keySet(), che è un insieme di oggetti che implementa l’interfaccia Iterable. Poi passando le chiavi al metodo get() si possono ottenere i valori.

// mappa: Matricola (Integer) -> Studente (Persona)
Map<Integer, Persona> mappa = new HashMap<>(); 
mappa.put("60237, new Persona("Mario", "Rossi"));
mappa.put("75022", new Persona("Luca", "Bianchi"));
 
for (Integer chiave : mappa.keySet()) {
   Persona persona = mappa.get(chiave);
   System.out.println(persona);
}

Metodo forEach

Tutte le collezione estendendo Collection che a sua volta estende Iterable ereditano il metodo forEach, metodo utilizzato per eseguire un’azione su ogni elemento di una collezione.

`forEach(Consumer<?> action)`

Questo metodo prende in input un Consumer, ovvero un’interfaccia funzionale che contiene un metodo chiamato accept(T ogg).

Il metodo accept() dell’interfaccia Consumer viene chiamato per ogni elemento della collezione, passando l’elemento come input. In questo modo, è possibile eseguire un’azione personalizzata su ogni elemento della collezione.

Essendo Consumer una classe funzionale ci sono diversi modi per implementarla, usando una lambda function, una classe anonima, un riferimento a metodo o implementandolo esplicitamente.

persone.forEach(p -> System.out.println(p)

Anche se le Mappe non estendo collection o Iterable hanno comunque una loro implementazione di forEach(BiConsumer<K, V>) che utilizza un BiConsumer ovvero un consumer ma con due oggetti generici in input invece di 1.