La Clausola finally in Java

Concetti Chiave
  • La clausola finally in Java garantisce l'esecuzione di un blocco di codice dopo un blocco try/catch, indipendentemente dalla presenza o meno di eccezioni.
  • È utile per garantire che determinate operazioni, come la chiusura di file o il rilascio di risorse, vengano sempre eseguite, anche in caso di errori.
  • Il blocco finally è opzionale, ma ogni istruzione try richiede almeno un blocco catch o un blocco finally.

Clausola finally

Quando vengono generate delle eccezioni, l'esecuzione in un metodo assume un percorso piuttosto brusco e non lineare che altera il normale flusso del metodo.

A seconda di come è stato codificato il metodo, è persino possibile che un'eccezione causi l'uscita anticipata dal metodo. Questo può costituire un problema in alcuni metodi. Ad esempio, se un metodo apre un file all'ingresso e lo chiude all'uscita, allora non si vorrà che il codice che chiude il file venga bypassato dal meccanismo di gestione delle eccezioni.

La parola chiave finally è stata progettata per affrontare questa eventualità.

finally crea un blocco di codice che verrà eseguito dopo che un blocco try/catch è stato completato e prima del codice che segue il blocco try/catch.

Il blocco finally verrà eseguito sia che venga generata un'eccezione, sia che non venga generata.

Se viene generata un'eccezione, il blocco finally verrà eseguito anche se nessuna istruzione catch corrisponde all'eccezione.

Ogni volta che un metodo sta per restituire il controllo al chiamante da dentro un blocco try/catch, tramite un'eccezione non catturata o un'istruzione return esplicita, il blocco finally viene anch'esso eseguito poco prima che il metodo ritorni. Questo può essere utile per chiudere file o liberare altre risorse che potrebbero essere state allocate all'inizio di un metodo con l'intento di essere smaltite prima del ritorno.

Il blocco finally è opzionale. Tuttavia, ogni istruzione try richiede almeno un blocco catch o un blocco finally.

Ecco un esempio di programma che mostra tre metodi che terminano in modi diversi, nessuno dei quali esce senza eseguire i rispettivi blocchi finally:

// Dimostrare finally.
class DemoFinally {
    // Generare un'eccezione fuori dal metodo.
    static void metodoA() {
        try {
            System.out.println("dentro metodoA");
            throw new RuntimeException("demo");
        } finally {
            System.out.println("finally di metodoA");
        }
    }

    // Restituire da dentro un blocco try.
    static void metodoB() {
        try {
            System.out.println("dentro metodoB");
            return;
        } finally {
            System.out.println("finally di metodoB");
        }
    }

    // Eseguire un blocco try normalmente.
    static void metodoC() {
        try {
            System.out.println("dentro metodoC");
        } finally {
            System.out.println("finally di metodoC");
        }
    }

    public static void main(String[] args) {
        try {
            metodoA();
        } catch (Exception e) {
            System.out.println("Eccezione catturata");
        }

        metodoB();
        metodoC();
    }
}

In questo esempio, metodoA() esce prematuramente dal blocco try generando un'eccezione. Il blocco finally viene eseguito durante l'uscita. Il blocco try di metodoB() viene terminato tramite un'istruzione return. Il blocco finally viene eseguito prima che metodoB() ritorni. In metodoC(), l'istruzione try viene eseguita normalmente, senza errori. Tuttavia, anche in questo caso il blocco finally viene eseguito.

Nota

Esecuzione garantita di finally

Se un blocco finally è associato a un try, il blocco finally verrà eseguito alla conclusione del try in qualunque caso.

Ecco l'output generato dal programma precedente:

dentro metodoA
finally di metodoA
Eccezione catturata
dentro metodoB
finally di metodoB
dentro metodoC
finally di metodoC