"Ciao, Amigo. Oggi faremo una lezione molto interessante. Ti parlerò delle eccezioni. Le eccezioni sono un meccanismo speciale che ci consente di gestire gli errori nel programma. Ecco alcuni esempi di errori che potrebbero verificarsi in un programma:

1. Il programma potrebbe provare a scrivere un file quando il disco rigido è completamente pieno.

2. Il programma potrebbe provare a chiamare un metodo su una variabile che memorizza un riferimento nullo.

3. Il programma potrebbe tentare di dividere un numero per 0."

Tutte queste azioni provocano errori. Di solito, il risultato è che il programma termina immediatamente, poiché in questo caso non ha senso continuare l'esecuzione del codice.

"Perché?"

"Ha senso continuare a girare una ruota se l'auto è uscita di strada e sta cadendo da un dirupo?"

"Il programma dovrebbe smettere di funzionare, allora?"

"Sì. Almeno, questo è quello che succedeva. Qualsiasi errore causava la chiusura del programma."

"Questo è un approccio molto intelligente."

"Ma non sarebbe meglio provare a continuare a eseguire il programma?"

"Sì. Supponi di aver digitato un'enorme quantità di testo in Word e di averlo salvato. E se l'operazione di salvataggio fallisce, ma il programma ti porta a credere che sia tutto a posto? E tu continui a digitare. Sarebbe stupido, no Esso?"

"Sì."

"Quindi i programmatori hanno trovato una soluzione interessante: ogni funzione avrebbe restituito lo stato del suo lavoro. 0 significava che funzionava come previsto. Qualsiasi altro valore significava che si era verificato un errore e il valore restituito era un codice di errore."

"Tuttavia, anche questo approccio ha i suoi difetti. Dopo ogni (!) chiamata di funzione, devi controllare il codice di ritorno (numero). Prima di tutto, questo è scomodo: il codice di gestione degli errori viene raramente eseguito ma deve essere incluso ovunque. In secondo luogo, le funzioni spesso restituiscono valori diversi: cosa dovresti farne?"

"Giusto. Ci ho pensato anch'io."

"Quindi, è arrivato un brillante futuro sotto forma di eccezioni e un meccanismo di gestione degli errori. Ecco come funziona:

1. Quando si verifica un errore, la macchina Java crea un oggetto speciale, un'eccezione, in cui salva tutte le informazioni sull'errore. Ci sono diverse eccezioni per diversi errori.

2. Un'eccezione fa sì che il programma esca immediatamente dalla funzione corrente, dalla funzione successiva e così via, finché non esce dal metodo principale. Quindi il programma termina. I programmatori possono anche dire che la Java Machine 'srotola lo stack di chiamate'."

"Ma hai detto che il programma non sempre termina."

"Sì, perché c'è un modo per catturare un'eccezione. Possiamo scrivere un codice speciale nel posto giusto per catturare le eccezioni che ci interessano e fare qualcosa con loro. Questa è roba importante."

"Per aiutarci in questo, c'è uno speciale costrutto try-catch . Ecco come funziona:"

Esempio di un programma che rileva un'eccezione (divisione per 0) e continua a funzionare.
public class ExceptionExample2
{
    public static void main(String[] args)
    {
        System.out.println("Program starts");

        try
        {
            System.out.println("Before calling method1");
            method1();
            System.out.println("After calling method1. This will never be shown");
        }
        catch (Exception e)
        {
           System.out.println("Exception has been caught");
        }

        System.out.println("Program is still running");
    }

    public static void method1()
    {
        int a = 100;
        int b = 0;
        System.out.println(a / b);
    }
}
Uscita sullo schermo:
Program starts
Before method1 calling
Exception has been caught
Program is still running

"Ma perché 'Dopo aver chiamato metodo1. Questo non verrà mai mostrato' non verrà visualizzato sullo schermo?"

"Sono contento che tu l'abbia chiesto. Nella riga 25, dividiamo per 0, il che porta a un errore: un'eccezione. La Java Machine crea un oggetto ArithmeticException con informazioni sull'errore. L'oggetto è l'eccezione."

"L'eccezione si verifica all'interno del method1metodo. Questo fa sì che il metodo termini immediatamente. Se non fosse per il blocco try-catch, causerebbe la chiusura del metodo main ."

"Se si verifica un'eccezione all'interno di un blocco try, viene rilevata nel blocco catch . Il resto del codice nel blocco try non verrà eseguito. Invece, inizierà l'esecuzione del blocco catch . "

"Non capisco."

"In altre parole, il codice funziona così:

1. Se si verifica un'eccezione all'interno di un blocco try, il codice cessa di essere eseguito nel punto in cui si è verificata l'eccezione e inizia l'esecuzione del blocco catch .

2. Se non si verifica alcuna eccezione , il blocco try viene eseguito fino alla fine e il blocco catch non viene eseguito. "

"Eh?"

"Immagina che dopo ogni chiamata di metodo controlliamo se il metodo è tornato normalmente o è stato interrotto bruscamente a causa di un'eccezione. Se c'è un'eccezione, allora passiamo all'esecuzione del blocco catch (se ce n'è uno) per catturare l'eccezione. Se non è presente alcun blocco catch, terminiamo il metodo corrente e il metodo che ci ha chiamato esegue lo stesso controllo."

"Penso di averlo capito ora."

"Eccellente."

"Cosa significa 'Eccezione' all'interno dell'istruzione catch?"

" Tutte le eccezioni sono classi che ereditano la classe Exception. Possiamo catturare una particolare eccezione specificando la classe di eccezione nel blocco catch , oppure possiamo catturare tutte le eccezioni specificando la loro classe genitore comune - Exception. Quindi possiamo ottenere tutti gli errori necessari informazioni dalla variabile e (memorizza un riferimento all'oggetto eccezione)."

"Fantastico! Se nel mio metodo si verificano diverse eccezioni, posso elaborarle in modo diverso?"

"Non solo puoi, ma dovresti. Puoi farlo in questo modo:"

Esempio:
public class ExceptionExample2
{
    public static void main(String[] args)
    {
        System.out.println("Program starts");

        try
        {
            System.out.println("Before calling method1");
            method1();
            System.out.println("After calling method1. This will never be shown");
        }
        catch (NullPointerException e)
        {
           System.out.println("Null reference. Exception has been caught");
        }
        catch (ArithmeticException e)
        {
            System.out.println("Division by zero. Exception has been caught");
        }
        catch (Exception e)
        {
            System.out.println("Any other errors. Exception has been caught");
        }

        System.out.println("Program is still running");
    }

    public static void method1()
    {
        int a = 100;
        int b = 0;
        System.out.println(a / b);
    }
}

"Il blocco try può essere associato a diversi blocchi catch , ognuno dei quali rileverà i tipi di eccezioni specificati."

"Penso di capire. Non posso ancora scriverlo da solo, ma se lo trovo in codice, non mi spaventerò."