Ciclo for-each in Java

Concetti Chiave
  • Il ciclo for-each in Java consente di iterare su ogni elemento di un array o di una collezione senza la necessità di gestire manualmente gli indici.
  • La sintassi del ciclo for-each è for(tipo nome_var : collezione) blocco-istruzioni, dove tipo è il tipo degli elementi nella collezione e nome_var è la variabile che riceve gli elementi uno alla volta.
  • Il ciclo for-each è utile per semplificare il codice e ridurre il rischio di errori di indicizzazione, poiché non richiede la gestione manuale degli indici.

La Versione for-each del Ciclo for

Una seconda forma di for implementa un ciclo in stile per ogni, ossia itera su ogni elemento di una collezione.

Tutti i moderni linguaggi di programmazione hanno introdotto questa funzionalità, ed è diventato quasi una caratteristica standard.

Un ciclo in stile for-each è progettato per scorrere attraverso una collezione di oggetti, come un array, in modo strettamente sequenziale. Poiché il ciclo for tradizionale richiede che il programmatore stabilisca un contatore del ciclo, un valore di inizio e fine, e indicizzi manualmente la collezione, il ciclo for-each semplifica notevolmente questo processo ed è spesso chiamato enhanced for loop o for-each loop.

La forma generale della versione for-each del for è mostrata qui:

for(tipo nome_var : collezione) blocco-istruzioni

Qui, tipo specifica il tipo e nome_var specifica il nome di una variabile di iterazione che riceverà gli elementi da una collezione, uno alla volta, dall'inizio alla fine.

La collezione che viene scorsa è specificata da collezione. Ci sono vari tipi di collezioni che possono essere usate con il ciclo for, ma l'unico tipo discusso in questa lezione è l'array. (Altri tipi di collezioni che possono essere usate con il for, come quelle definite dal Collections Framework, sono discusse nelle prossime lezioni).

Con ogni iterazione del ciclo, l'elemento successivo nella collezione viene recuperato e memorizzato in nome_var. Il ciclo si ripete finché tutti gli elementi nella collezione sono stati ottenuti.

Poiché la variabile di iterazione riceve valori dalla collezione, tipo deve essere dello stesso tipo (o compatibile con) degli elementi memorizzati nella collezione. Così, quando si itera sugli array, tipo deve essere compatibile con il tipo di elemento dell'array.

Per comprendere la motivazione dietro un ciclo for-each, si consideri il tipo di ciclo for che è progettato per sostituire. Il seguente frammento usa un ciclo for tradizionale per calcolare la somma dei valori in un array:

int[] numeri = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int somma = 0;

for(int i=0; i < 10; i++)
    somma += numeri[i];

Per calcolare la somma, ogni elemento in numeri viene letto, in ordine, dall'inizio alla fine. Così, l'intero array viene letto in ordine strettamente sequenziale. Questo è realizzato indicizzando manualmente l'array numeri tramite la variabile del ciclo i.

Lo stile for-each for automatizza il ciclo precedente. Specificamente, elimina la necessità di stabilire un contatore del ciclo, specificare un valore di inizio e fine, e indicizzare manualmente l'array. Invece, automaticamente scorre attraverso l'intera sequenza di array, ottenendo un elemento alla volta, in sequenza, dall'inizio alla fine. Per esempio, qui è il frammento precedente riscritto usando una versione for-each del for:

int[] numeri = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int somma = 0;

for(int x: numeri) somma += x;

Con ogni passaggio attraverso il ciclo, x riceve automaticamente un valore uguale all'elemento successivo in numeri. Così, nella prima iterazione, x contiene 1; nella seconda iterazione, x contiene 2; e così via. Non solo la sintassi è semplificata, ma previene anche errori di sfondamento dell'array.

Ecco un intero programma che dimostra la versione for-each del for appena descritta:

// Usa un ciclo for in stile for-each.
class ForEach {
    public static void main(String[] args) {
        int[] numeri = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        int somma = 0;

        // usa lo stile for-each per visualizzare e sommare i valori
        for(int x : numeri) {
            System.out.println("Valore è: " + x);
            somma += x;
        }

        System.out.println("Somma: " + somma);
    }
}

L'output del programma è mostrato qui:

Valore è: 1
Valore è: 2
Valore è: 3
Valore è: 4
Valore è: 5
Valore è: 6
Valore è: 7
Valore è: 8
Valore è: 9
Valore è: 10
Somma: 55

Come mostra questo output, lo stile for-each for scorre automaticamente attraverso un array in sequenza dall'indice più basso al più alto.

Anche se il ciclo for-each for itera finché tutti gli elementi in un array sono stati esaminati, è possibile terminare il ciclo anticipatamente usando un'istruzione break. Per esempio, questo programma somma solo i primi cinque elementi di numeri:

// Usa break con un for in stile for-each.
class ForEach2 {
    public static void main(String[] args) {
        int somma = 0;
        int[] numeri = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        // usa for per visualizzare e sommare i valori
        for(int x : numeri) {
            System.out.println("Valore è: " + x);
            somma += x;
            if(x == 5) break; // ferma il ciclo quando 5 è ottenuto
        }
        System.out.println("Somma dei primi 5 elementi: " + somma);
    }
}

Questo è l'output prodotto:

Valore è: 1
Valore è: 2
Valore è: 3
Valore è: 4
Valore è: 5
Somma dei primi 5 elementi: 15

Come è evidente, il ciclo for si ferma dopo che il quinto elemento è stato ottenuto.

C'è un punto importante da comprendere riguardo al ciclo in stile for-each. La sua variabile di iterazione è di sola lettura per quanto riguarda l'array sottostante. Un'assegnazione alla variabile di iterazione non ha effetto sull'array sottostante. In altre parole, non è possibile cambiare i contenuti dell'array assegnando alla variabile di iterazione un nuovo valore. Per esempio, consideriamo questo programma:

// Il ciclo for-each è essenzialmente read-only.
class NoCambiamento {
    public static void main(String[] args) {
        int[] numeri = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        for(int x: numeri) {
            System.out.print(x + " ");
            x = x * 10; // nessun effetto su numeri
        }

        System.out.println();

        for(int x : numeri)
            System.out.print(x + " ");

        System.out.println();
    }
}

Il primo ciclo for aumenta il valore della variabile di iterazione di un fattore di 10. Tuttavia, questa assegnazione non ha effetto sull'array sottostante numeri, come illustra il secondo ciclo for. L'output, mostrato qui, prova questo punto:

1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10

Come si può vedere, l'array numeri non è stato modificato dal ciclo for-each.