Istruzione break in Java

Concetti Chiave
  • L'istruzione break interrompe immediatamente l'esecuzione di un ciclo o un blocco switch.
  • Può essere utilizzata in cicli (for, while) per prevenire ulteriori iterazioni quando una condizione viene soddisfatta.
  • In cicli annidati, il break interrompe solo il ciclo più interno, a meno che non venga usato un break etichettato.
  • Il break etichettato permette di uscire da più livelli di cicli o blocchi annidati, similmente a un goto controllato.
  • L'abuso della dichiarazione break può rendere il codice meno leggibile; è preferibile usare le normali condizioni dei cicli per il controllo del flusso.

Istruzioni di salto

Java supporta tre istruzioni di salto: break, continue e return.

Queste istruzioni trasferiscono il controllo a un'altra parte del programma. In questa lezione ci concentreremo sull'istruzione break. Le istruzioni continue e return sono trattate nelle prossime lezioni.

Consiglio

Gestione delle eccezioni come alternativa

Oltre alle istruzioni di salto qui trattate, Java offre un altro modo per modificare il flusso di esecuzione del programma: la gestione delle eccezioni.

La gestione delle eccezioni fornisce un metodo strutturato mediante il quale gli errori di run-time possono essere intercettati e gestiti dal programma. È supportata dalle parole chiave try, catch, throw, throws e finally.

In sostanza, il meccanismo di gestione delle eccezioni consente al programma di effettuare un ramo non locale. Poiché la gestione delle eccezioni è un argomento ampio, lo tratteremo in dettaglio nelle lezioni successive.

L'istruzione break

In Java, l'istruzione break ha tre impieghi:

  1. Come già visto, termina una sequenza di istruzioni in uno switch.
  2. Può essere usata per uscire da un ciclo.
  3. Può fungere da forma migliorata di goto.

Avendo visto già il primo impiego, in questa lezione ci concentreremo sugli altri due.

Uso di break per uscire da un ciclo

Mediante break è possibile forzare l'interruzione immediata di un ciclo, ignorando l'espressione condizionale e qualsiasi codice rimanente nel corpo del ciclo.

Quando viene incontrata un'istruzione break all'interno di un ciclo, il ciclo viene terminato e il controllo del programma riprende con l'istruzione successiva al ciclo.

Ecco un semplice esempio:

// Uso di break per uscire da un ciclo.
class InterrompiCiclo {
    public static void main(String[] args) {
        for (int indice = 0; indice < 100; indice++) {
            if (indice == 10) break; // termina il ciclo se indice vale 10
            System.out.println("indice: " + indice);
        }
        System.out.println("Ciclo completato.");
    }
}

Questo programma produce il seguente output:

indice: 0
indice: 1
indice: 2
indice: 3
indice: 4
indice: 5
indice: 6
indice: 7
indice: 8
indice: 9
Ciclo completato.

Come si può vedere, sebbene il ciclo for sia predisposto per l'esecuzione da 0 a 99, l'istruzione break lo fa terminare anticipatamente, quando indice vale 10.

L'istruzione break può essere utilizzata con qualsiasi ciclo di Java, compresi i cicli intenzionalmente infiniti. Ad esempio, ecco il programma precedente riscritto mediante un ciclo while. L'output di questo programma è lo stesso appena mostrato.

// Uso di break per uscire da un ciclo while.
class InterrompiCiclo2 {
    public static void main(String[] args) {
        int indice = 0;

        while (indice < 100) {
            if (indice == 10) break; // termina il ciclo se indice vale 10
            System.out.println("indice: " + indice);
            indice++;
        }
        System.out.println("Ciclo completato.");
    }
}

Quando break è usato all'interno di un insieme di cicli annidati, interrompe solo il ciclo più interno. Per esempio:

// Uso di break con cicli annidati.
class InterrompiCiclo3 {
    public static void main(String[] args) {
        for (int passaggio = 0; passaggio < 3; passaggio++) {
            System.out.print("Passaggio " + passaggio + ": ");
            for (int indiceInterno = 0; indiceInterno < 100; indiceInterno++) {
                // termina il ciclo se indiceInterno vale 10
                if (indiceInterno == 10) break;
                System.out.print(indiceInterno + " ");
            }
            System.out.println();
        }
        System.out.println("Cicli completati.");
    }
}

Questo programma genera il seguente output:

Passaggio 0: 0 1 2 3 4 5 6 7 8 9 
Passaggio 1: 0 1 2 3 4 5 6 7 8 9 
Passaggio 2: 0 1 2 3 4 5 6 7 8 9 
Cicli completati.

Come si può notare, l'istruzione break nel ciclo interno provoca la terminazione solo di quel ciclo. Il ciclo esterno rimane inalterato.

Vi sono altri due aspetti da ricordare riguardo a break:

  1. In un ciclo possono comparire più istruzioni break; tuttavia è opportuno fare attenzione, poiché un numero eccessivo di break tende a destrutturare il codice.
  2. Il break che termina un'istruzione switch influisce solo su quello switch e non su eventuali cicli racchiudenti.
Nota

Cercare di non abusare dell'istruzione break

break non è stato progettato come mezzo normale per terminare un ciclo. A tale scopo serve l'espressione condizionale del ciclo. L'istruzione break andrebbe utilizzata per annullare un ciclo solo quando si verifica una situazione particolare.

Uso di break come forma di goto

Oltre ai suoi utilizzi con l'istruzione switch e con i cicli, l'istruzione break può anche essere impiegata da sola per offrire una forma migliorata dell'istruzione goto.

Java non possiede l'istruzione goto perché essa consente di ramificare in modo arbitrario e non strutturato, rendendo di solito il codice pieno di goto difficile da comprendere e da mantenere, oltre a impedire alcune ottimizzazioni del compilatore.

Esistono tuttavia pochi casi in cui il goto rappresenta un costrutto valido e legittimo per il controllo di flusso. Per esempio, un goto può essere utile quando occorre uscire da un insieme profondamente annidato di cicli. Per gestire tali situazioni, Java definisce una forma estesa dell'istruzione break. Utilizzando questa forma di break è possibile, per esempio, uscire da uno o più blocchi di codice. Questi blocchi non devono far parte di un ciclo o di uno switch; possono essere qualsiasi blocco.

Inoltre, è possibile specificare con esattezza dove riprenderà l'esecuzione, poiché questa forma di break funziona con un'etichetta. In tal modo, break offre i vantaggi di un goto senza i relativi problemi.

La forma generale di un'istruzione break etichettata è mostrata qui:

break etichetta;

Nella maggior parte dei casi, etichetta è il nome di un'etichetta che identifica un blocco di codice.

Può essere un blocco autonomo, ma può anche essere il blocco bersaglio di un'altra istruzione. Quando questa forma di break viene eseguita, il controllo viene trasferito fuori dal blocco etichettato.

Il blocco etichettato deve racchiudere l'istruzione break, ma non è necessario che sia il blocco immediatamente più interno. Ciò significa, per esempio, che si può usare un break etichettato per uscire da una serie di blocchi annidati. Non è invece possibile usare break per trasferire il controllo fuori da un blocco che non racchiude l'istruzione break.

Per assegnare un nome a un blocco, bisogna porre un'etichetta all'inizio del blocco stesso. Un'etichetta è un qualsiasi identificatore Java valido seguito da due punti.

Una volta etichettato un blocco, si può usare tale etichetta come bersaglio di un'istruzione break. In tal modo l'esecuzione riprende alla fine del blocco etichettato. Per esempio, il programma seguente mostra tre blocchi annidati, ciascuno con la propria etichetta. L'istruzione break fa avanzare l'esecuzione oltre la fine del blocco etichettato secondo, saltando le due istruzioni println().

// Uso di break come forma civilizzata di goto.
class Interrompi {
    public static void principale(String[] argomenti) {
        boolean vero = true;

        primo: {
            secondo: {
                terzo: {
                    System.out.println("Prima dell'interruzione.");
                    if (vero) break secondo; // esce dal blocco secondo
                    System.out.println("Questo non verrà eseguito");
                }
                System.out.println("Questo non verrà eseguito");
            }
            System.out.println("Questo è dopo il blocco secondo.");
        }
    }
}

Esecuzione del programma:

Prima dell'interruzione.
Questo è dopo il blocco secondo.

Uno degli usi più comuni di un break etichettato è l'uscita da cicli annidati. Nel programma seguente, per esempio, il ciclo esterno viene eseguito una sola volta:

// Uso di break per uscire da cicli annidati.
class InterrompiCiclo4 {
    public static void principale(String[] argomenti) {
        esterno: for (int passaggio = 0; passaggio < 3; passaggio++) {
            System.out.print("Passaggio " + passaggio + ": ");
            for (int indiceInterno = 0; indiceInterno < 100; indiceInterno++) {
                if (indiceInterno == 10) break esterno; // esce da entrambi i cicli
                System.out.print(indiceInterno + " ");
            }
            System.out.println("Questo non verrà stampato");
        }
        System.out.println("Cicli completati.");
    }
}

Questo programma produce il seguente output:

Passaggio 0: 0 1 2 3 4 5 6 7 8 9 Cicli completati.

Come si può notare, quando il ciclo interno esegue il break verso il ciclo esterno, entrambi i cicli vengono terminati. Si osservi che in questo esempio viene etichettato l'istruzione for, che possiede un blocco di codice come bersaglio.

È importante ricordare che non è possibile eseguire un break verso un'etichetta che non sia definita per un blocco racchiudente. Il programma seguente, per esempio, è errato e non viene compilato:

// Questo programma contiene un errore.
class InterrompiErr {
    public static void principale(String[] argomenti) {

        uno: for (int passaggio = 0; passaggio < 3; passaggio++) {
            System.out.print("Passaggio " + passaggio + ": ");
        }

        for (int indiceInterno = 0; indiceInterno < 100; indiceInterno++) {
            if (indiceInterno == 10) break uno; // ERRATO
            System.out.print(indiceInterno + " ");
        }
    }
}

Poiché il ciclo etichettato uno non racchiude l'istruzione break, non è possibile trasferire il controllo fuori da quel blocco.