Ciclo for in Java

Concetti Chiave
  • Il ciclo for in Java è una struttura di controllo potente e versatile, utilizzata per eseguire un blocco di codice un numero specifico di volte.
  • Esistono due forme di ciclo for: la tradizionale e la for-each, ma in questa lezione si esamina solo la forma tradizionale.
  • La sintassi generale del ciclo for include tre parti: inizializzazione, condizione e iterazione.
  • La variabile di controllo del ciclo può essere dichiarata all'interno del for, limitando il suo ambito al ciclo stesso.
  • È possibile utilizzare la virgola per includere più istruzioni nelle parti di inizializzazione e iterazione del ciclo.
  • Con il ciclo for è possibile adoperare l'inferenza del tipo di variabile locale, introdotta in JDK 10, per dedurre il tipo della variabile di controllo del ciclo.

Ciclo for

Si è già visto un semplice utilizzo del ciclo for nelle lezioni precedenti. Come sarà evidente, si tratta di una struttura potente e versatile.

Esistono due forme di ciclo for. La prima è la forma tradizionale, in uso fin dalla versione originale di Java. La seconda è la forma più recente for-each, aggiunta con JDK 5. In questa lezione si esaminerà la forma tradizionale del ciclo for.

Ecco la forma generale dell'istruzione for tradizionale:

for(inizializzazione; condizione; iterazione) {
    // corpo
}

Se viene ripetuta una sola istruzione, le parentesi graffe non sono necessarie.

Il ciclo for opera come segue:

  1. All'avvio del ciclo viene eseguita la parte di inizializzazione. In genere si tratta di un'espressione che assegna un valore alla variabile di controllo del ciclo, la quale funge da contatore. L'espressione di inizializzazione viene eseguita una sola volta.
  2. Successivamente viene valutata la condizione, che deve essere un'espressione booleana.

    Di solito la condizione confronta la variabile di controllo con un valore obiettivo. Se l'espressione è vera, viene eseguito il corpo del ciclo; se è falsa, il ciclo termina.

  3. Poi viene eseguita la parte di iterazione, normalmente un'espressione che incrementa o decrementa la variabile di controllo.

  4. Il ciclo procede quindi valutando la condizione, eseguendo il corpo e infine l'espressione di iterazione a ogni passaggio, finché l'espressione di controllo risulta falsa.

Riprendiamo l'esempio del ciclo tic visto in precedenza, che conta da 10 a 1. Il ciclo for è una struttura di controllo che consente di eseguire un blocco di codice un numero specifico di volte, rendendolo ideale per questo tipo di operazioni.

// Dimostrazione del ciclo for.
class ForTic {
    public static void main(String[] args) {
        int n;

        for(n = 10; n > 0; n--)
            System.out.println("tic " + n);
    }
}

Dichiarare la variabile di controllo all'interno del for

Spesso la variabile che controlla un ciclo for serve solo all'interno del ciclo stesso e non altrove. In tal caso è possibile dichiarare la variabile direttamente nella parte di inizializzazione del for. Di seguito, lo stesso programma precedente è riscritto dichiarando n come int all'interno del for:

// Dichiarare una variabile di controllo all'interno del for.
class ForTic {
    public static void main(String[] args) {

        // qui, n è dichiarata all'interno del ciclo for
        for(int n = 10; n > 0; n--)
            System.out.println("tic " + n);
    }
}

Quando una variabile viene dichiarata all'interno di un ciclo for, il suo ambito termina con l'istruzione for stessa (ovvero è limitato al ciclo). Fuori dal ciclo la variabile cessa di esistere. Se occorre utilizzare la variabile di controllo altrove nel programma, non sarà possibile dichiararla all'interno del for.

Quando la variabile di controllo non serve altrove, la maggior parte dei programmatori Java la dichiara all'interno del for. Ad esempio, il seguente programma verifica se un numero è primo; si noti che la variabile di controllo i è dichiarata nel for, poiché non è necessaria altrove.

// Verifica dei numeri primi.
class TrovaPrimo {
    public static void main(String[] args) {
        int numero;
        boolean èPrimo;

        numero = 14;

        if(numero < 2) èPrimo = false;
        else            èPrimo = true;

        for(int i = 2; i <= numero / i; i++) {
            if((numero % i) == 0) {
                èPrimo = false;
                break;
            }
        }

        if(èPrimo) System.out.println("Primo");
        else       System.out.println("Non primo");
    }
}

Uso della virgola

Talvolta è necessario includere più di un'istruzione nelle parti di inizializzazione e iterazione del ciclo for. Si consideri il ciclo nel programma seguente:

class Esempio {
    public static void main(String[] args) {
        int a, b;

        b = 4;
        for(a = 1; a < b; a++) {
            System.out.println("a = " + a);
            System.out.println("b = " + b);
            b--;
        }
    }
}

Il ciclo è controllato dall'interazione di due variabili. Poiché il ciclo dipende da entrambe, sarebbe utile includerle entrambe nell'istruzione for, invece di gestire b manualmente. Java consente di farlo inserendo più istruzioni sia nella parte di inizializzazione sia in quella di iterazione, separate da virgole.

Riscrivendo il ciclo precedente con la virgola si ottiene:

// Uso della virgola.
class Virgola {
    public static void main(String[] args) {
        int a, b;

        for(a = 1, b = 4; a < b; a++, b--) {
            System.out.println("a = " + a);
            System.out.println("b = " + b);
        }
    }
}

In questo esempio, la parte di inizializzazione assegna i valori sia di a sia di b. Le due istruzioni separate da virgola nella parte di iterazione vengono eseguite a ogni ripetizione del ciclo. Il programma produce il seguente output:

a = 1
b = 4
a = 2
b = 3

Alcune varianti del ciclo for

Il ciclo for offre numerose varianti che ne ampliano potenza e applicabilità. La sua flessibilità deriva dal fatto che le sue tre parti—inizializzazione, test condizionale e iterazione—non devono essere utilizzate esclusivamente per tali scopi: ciascuna può contenere qualunque espressione.

Una variante comune riguarda l'espressione condizionale: non è necessario confrontare la variabile di controllo con un valore obiettivo; la condizione può essere qualunque espressione booleana. Si osservi il frammento seguente:

boolean finito = false;

for(int i = 1; !finito; i++) {
    // ...
    if(interrupted()) finito = true;
}

Il ciclo continua finché la variabile booleana finito diventa true. Non viene testato il valore di i.

Un'altra variante prevede che l'espressione di inizializzazione o quella di iterazione, o entrambe, possano essere assenti, come nel programma seguente:

// Parti del ciclo for possono essere vuote.
class PerVar {
    public static void main(String[] args) {
        int i;
        boolean finito = false;

        i = 0;
        for( ; !finito; ) {
            System.out.println("i vale " + i);
            if(i == 10) finito = true;
            i++;
        }
    }
}

Qui le espressioni di inizializzazione e di iterazione sono state spostate fuori dal for, lasciando tali parti vuote. Pur essendo uno stile discutibile in un esempio così semplice, in alcune situazioni può avere senso.

Se, ad esempio, la condizione iniziale è stabilita da un'espressione complessa altrove nel programma o se la variabile di controllo cambia in modo non sequenziale in base ad azioni all'interno del corpo del ciclo, può essere opportuno lasciare vuote queste parti del for.

Un'ulteriore variante consente di creare intenzionalmente un ciclo infinito (che non termina mai) lasciando vuote tutte e tre le parti del for:

for( ; ; ) {
    // ...
}

Questo ciclo continua indefinitamente perché manca una condizione di terminazione. Sebbene alcuni programmi, come i processori di comandi dei sistemi operativi, richiedano un ciclo infinito, la maggior parte dei cosiddetti “cicli infiniti” sono semplicemente cicli con requisiti di terminazione particolari. Esiste comunque un modo per terminare un ciclo—anche uno infinito come quello mostrato—senza utilizzare l'espressione condizionale normale del ciclo. Lo vedremo nelle prossime lezioni.

Inferenza del Tipo di Variabile Locale in un Ciclo for

Come spiegato nelle lezioni precedenti, JDK 10 ha introdotto una funzionalità chiamata inferenza del tipo di variabile locale, che consente di dedurre il tipo di una variabile locale dal tipo del suo inizializzatore.

Per utilizzare l'inferenza del tipo di variabile locale, il tipo della variabile viene specificato come var e la variabile deve essere inizializzata.

L'inferenza del tipo di variabile locale può essere utilizzata in un ciclo for quando si dichiara e inizializza la variabile di controllo del ciclo all'interno di un for tradizionale.

Il programma seguente mostra come fare

// Utilizzare l'inferenza del tipo in un ciclo for.
class InferenzaTipoInFor {
    public static void main(String[] argomenti) {

        // Utilizzare l'inferenza del tipo con la variabile di controllo del ciclo.
        System.out.print("Valori di x: ");
        for (var x = 2.5; x < 100.0; x = x * 2)
            System.out.print(x + " ");
    }
}

L'output è il seguente:

Valori di x: 2.5 5.0 10.0 20.0 40.0 80.0

In questo esempio, la variabile di controllo del ciclo x in questa riga:

for (var x = 2.5; x < 100.0; x = x * 2)

viene dedotta di tipo double perché questo è il tipo del suo inizializzatore.