Programmare in .. Java – Le eccezioni

Il concetto di eccezione in Java è fondamentale, infatti molto spesso una porzione di codice non ha il comportamento atteso, per svariati motivi, e attraverso le eccezioni è possibile catturare, analizzare e risolvere questo comportamento.

Quando viene prodotto un errore, viene lanciata un’eccezione; ad esempio quando cercate di aprire un file che non esiste, darete luogo ad un’eccezione.

Questa eccezione, se non è gestita, da luogo alla terminazione del programma, o meglio del thread che l’ha lanciata, che nel caso sia il main, coincide con il programma.

Un’eccezione è un oggetto, come tutto in Java; è un istanza della classe Throwable, in particolare di due sue sottoclassi: Exception ed Error. Un Error è considerato irrecuperabile, mentre un Exception non lo è, e si può catturare e gestire.

Il funzionamento è il seguente: quando viene generata un’eccezione dentro un blocco di codice, questa viene propagata verso l’alto, finché non trova un gestore delle eccezioni; se non ne viene trovato nessuno, viene utilizzato quello di default, che vi stamperà la stringa di errore e farà terminare il programma. (In sostanza, se arriva al main senza essere gestita il programma terminerà).

Generare un’eccezione

All’interno di una qualsiasi porzione di codice, possiamo noi stessi generare un’eccezione, attraverso la parola chiave throw:

1
2
if (x==0)
   throw new Exception("Numero uguale a 0")

Come potete notare dall’esempio, un’eccezione è per forza un errore ma semplicemente un comportamento “eccezionale” che vogliamo notificare e gestire; quel blocco di codice ci potrebbe trovare all’interno di un codice che lavora solo su numeri negativi o positivi, che non possono essere zero.

Catturare un’eccezione

Per catturare un eccezione e quindi gestirla, si utilizza il costrutto try/catch; il concetto è che mettiamo il codice che può generare un eccezione all’interno di un blocco try e all’esterno di questo blocco, ne mettiamo uno catch, per catturare e gestire l’eccezione.

Ad esempio:

1
2
3
4
5
6
7
8
try
{
   apriFile("pippo.txt");
}
catch(FileNotFoundException e)
{
   System.err.println("Errore: File non trovato");
}

In questo esempio, cerco di aprire il file pippo.txt all’interno del blocco try! Se il file non dovesse esistere, verrebbe generata l’eccezione FileNotFoundException (sottoclasse della classe Exception) che verrebbe catturata dal blocco catch e stamperebbe quel messaggio.

Poiché tutte le eccezioni derivano da Exception, come spiegato nella lezione sull’ereditarietà, è possibile catturare una qualsiasi eccezione e il catch può essere più o meno generale.

Per esempio una FileNotFoundException non catturerebbe una IOException, invece potrei scrivere:

1
catch(Exception e) { ... }

In questo modo riuscirei a catturare tutte le eccezioni possibili.
E’ anche possibile mettere più blocchi catch in cascata, dopo un unico try, in modo da cercare di catturare le eccezioni singolarmente, ad esempio:

1
2
3
try { ... }
catch(FileNotFoundException e) { ... }
catch(IOException e) { ... }

Opzionalmente, alla fine del blocco try/catch, è possibile specificare un blocco finally, che verrà eseguito sempre e in ogni caso una volta, sia dopo il try che dopo il catch, in questo modo:

1
2
3
try { ... }
catch(Exception e) { ... }
finally { ... }

Rilanciare un’eccezione

In Java, un metodo che lancia un’eccezione all’interno può fare due cose:

  • Gestirla con il blocco try/catch appena visto;
  • Rilanciare l’eccezione verso colui che ha richiamato quel metodo.

In questo secondo caso, forzeremmo colui che ha chiamato il metodo a gestire l’eccezione e, a meno che sia il main, anche il chiamante può gestire l’eccezione o rilanciarla. L’unico metodo che non può rilanciare un’eccezione è il main, che deve obbligatoriamente gestirla, pena la terminazione del programma.

La sintassi per il rilancio dell’eccezione, passa dalla parola chiave throws e si deve dichiarare nella firma del metodo, ad esempio:

1
2
3
void apriFile(String nome) throws FileNotFoundException, IOException
{
}

Ovviamente, è possibile lanciare più di un’eccezione!

Adesso vediamo un esempio pratico per riassumere i concetti visti fino ad ora, e vi raccomando di eseguirlo per capire meglio anche voi:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try
{
   String a = "0";
   int r2 = Integer.parseInt(a) / Integer.parseInt(a);
}
catch (ArithmeticException e)
{
   System.out.println("Calculation Error");
}
catch (Exception e)
{
   System.out.println("General Exception");
}
finally
{
   System.out.println("Finally");
}
 
System.out.println("Finished");

Come vedete il codice istanzia una stringa e poi prova a fare una divisione per zero, che genera un’eccezione di tipo ArithmeticException; una volta generata, l’esecuzione passa a quel catch che stamperà Calculation Error.
Una volta eseguito il catch, l’esecuzione passa a finally, che stamperà Finally e infine si va fuori e viene eseguita l’istruzione che stampa Finished.

Al solito, se avete dubbi, commenti o critiche non esitate a commentare o a contattarmi.

Autore dell'articolo: TecnoNerd

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *