Ciclo for-each (Enhanced for) in Java
Itera su array e collezioni in Java con il ciclo for-each per un'iterazione più semplice e sicura.
Java 5 ha introdotto il ciclo for avanzato — comunemente chiamato ciclo for-each — per scorrere ogni elemento di un array o di una collezione senza dover gestire manualmente un indice. Quando non hai bisogno dell'indice, è quasi sempre la scelta più pulita.
Sintassi
for (Type element : iterable) {
// body — runs once per element
}Si legge come: per ogni element in iterable. I due punti sono obbligatori; non è la stessa cosa dei punti e virgola del ciclo for normale.
int[] nums = {10, 20, 30, 40};
for (int n : nums) {
System.out.println(n);
}Stampa 10 20 30 40. Nessun contatore, nessun nums.length, nessun nums[i].
Funziona su array e qualsiasi Iterable
Il ciclo for-each accetta:
- Qualsiasi array.
- Qualsiasi cosa che implementi
java.lang.Iterable<T>— il che significa ogniCollection(comeList,SeteQueue), oltre a molti altri tipi JDK e di libreria.
import java.util.List;
List<String> names = List.of("alice", "bob", "carol");
for (String name : names) {
System.out.println(name);
}
String text = "abc";
for (char c : text.toCharArray()) {
System.out.println(c);
}Nota che String in sé non è iterabile, ma text.toCharArray() produce un array, che lo è.
Una Map non è nemmeno direttamente Iterable — si itera su una delle sue viste: map.keySet(), map.values() o map.entrySet(). Ognuna di esse restituisce un Set o una Collection, che il ciclo for-each gestisce.
La variabile elemento è una copia
La variabile nell'intestazione del ciclo riceve il valore di ogni elemento. Per i tipi primitivi, modificarla non cambia l'array:
int[] nums = {1, 2, 3};
for (int n : nums) {
n *= 10; // doesn't touch nums
}
System.out.println(nums[0]); // still 1Per gli oggetti, la variabile contiene un riferimento, quindi chiamare metodi che mutano l'oggetto influirà sull'originale. Ma riassegnare la variabile (name = "...";) cambia solo la copia locale.
Se hai bisogno di modificare gli elementi stessi, usa un ciclo con indice:
for (int i = 0; i < nums.length; i++) {
nums[i] *= 10;
}Quando non puoi usare for-each
Un ciclo for-each nasconde l'indice. Questo è il punto — ma significa anche che non puoi usarlo quando hai bisogno di:
- L'indice (
"item " + i + ": " + value) - Rimuovere elementi durante l'iterazione (usa un
Iteratoresplicito e chiamaiterator.remove()) - Due collezioni in parallelo (usa gli indici)
- Iterare in ordine inverso o saltare elementi (usa un
forcon indice)
Non modificare la collezione durante l'iterazione
Un ciclo for-each su una collezione usa internamente un Iterator. Se modifichi la struttura della collezione durante l'iterazione (aggiungi o rimuovi elementi), l'iteratore si accorge della discrepanza al passo successivo e lancia una ConcurrentModificationException:
List<String> names = new ArrayList<>(List.of("alice", "bob"));
for (String n : names) {
names.remove(n); // ConcurrentModificationException
}Per rimuovere in modo sicuro, guida il ciclo con un Iterator esplicito e chiama il suo remove() — mantiene l'iteratore e la lista sincronizzati:
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String n = it.next();
if (n.startsWith("a")) {
it.remove(); // safe
}
}Con Java 8+ puoi spesso saltare del tutto il ciclo: names.removeIf(n -> n.startsWith("a"));.
Leggere o sostituire un elemento (list.set(i, x)) durante un ciclo for-each va bene. Sono solo le modifiche strutturali — add e remove sulla collezione stessa — a generare l'eccezione.
Un esempio pratico
Cosa viene dopo
Quando hai bisogno di uscire da un ciclo anticipatamente — o di saltare il resto dell'iterazione corrente — usa break e continue.