Вы находитесь на странице: 1из 18

Sessione 6

Eccezioni

1
La gestione delle eccezioni in Java
Le eccezioni in Java sono errori che si presentano durante lesecuzione del codice, ovvero a run-time.

Come detto nelle precedenti sessioni, le eccezioni appartengono alla categoria delle istruzioni che modificano il normale flusso
sequenziale di esecuzione del codice sorgente.

Guardiamo subito un esempio:

package com.azienda.esempiCorso.sessione6;

public class EsempioEccezioni1


{
public static void main(String args[])
{
try
{
int x = 3;
int y = 0;
int z = x/y;
System.out.println("z=" + z);
}
catch (Exception ex)
{

2
System.out.println("Si verificata un'eccezione -> siamo nel blocco catch");
ex.printStackTrace();
}
}

Ed ecco louput prodotto a video:

Si verificata un'eccezione -> siamo nel blocco catch


java.lang.ArithmeticException: / by zero
at com.azienda.progettoCorso.examples.exception.EsempioEccezioni1.main(EsempioEccezioni1.java:11)

Quando nel codice eseguito allinterno del blocco try/catch vengono eseguite delle operazioni che aprono risorse come
connessioni a file, connessioni a database, connessioni di rete (tutti concetti che vedremo pi avanti nel corso) e si vuole essere
sicuri di rilasciare le connessioni (quindi di chiuderle) prima di uscire dal blocco try/catch si aggiunge dopo il blocco catch un
blocco finally.

La JVM garantisce che qualsiasi cosa accada durante lesecuzione del codice try/catch, il blocco di codice interno alla clausola
finally verr comunque eseguito.

3
Esempio:

package com.azienda.esempiCorso.sessione6;

import java.io.FileInputStream;

public class EsempioEccezioniConFinally


{
public static void main(String args[]) throws Exception
{
FileInputStream fileInputStream = null;
try
{
int x = 3;
int y = 0;
fileInputStream = new FileInputStream("C:/temp/test.txt");
int z = x/y;
System.out.println("z=" + z);
}
catch (Exception ex)
{
int w = 5/0; /* forziamo appositamente un'altra eccezione per andare nel blocco finally*/
if ( fileInputStream != null )
{
fileInputStream.close(); /* questa istruzione non verr eseguita poich la precedente rilancia
un'eccezione */

4
}
System.out.println("Si verificata un'eccezione -> siamo nel blocco catch");
}
finally
{
/* qui dovremmo rilasciare eventuali risorse rimaste aperte */
System.out.println("Nel blocco finally");
if ( fileInputStream != null )
{
fileInputStream.close();
}
}
}

Loutput a video :

Exception in thread "main" java.lang.ArithmeticException: / by zero


Nel blocco finally
at
com.azienda.progettoCorso.examples.exception.EsempioEccezioniConFinally.main(EsempioEccezioniConFinally.java:20)

5
Nel codice riportato tralasciamo per un attimo i dettagli della classe FileInputStream, che discuteremo pi avanti nel corso, per
ora occorre solo sapere che un oggetto di classe FileInputStream rappresenta un file aperto in lettura.

Come possiamo vedere dal codice, abbiamo aperto un file in lettura nel blocco try, poi il codice rilancia uneccezione e il flusso
di esecuzione passa al blocco catch allinterno del quale proviamo a chiudere la connessione al file. Per anche il codice del
blocco catch rilancia uneccezione (nellesempio lo abbiamo fatto forzatamente a scopo dimostrativo con una divisione per zero)
e leccezione viene rilanciata prima dellistruzione di chiusura del file. In questo caso il flusso di esecuzione passa al blocco
finally dove, come dice la parola, finalmente, viene chiusa la connessione.

Abbiamo visto che listruzione x/y, genera un errore. In termini Java si dice che rilancia una Exception. Ci determina che il
flusso sequenziale di istruzioni viene interrotto: al posto di eseguire listruzione System.out.println(Z = + z), verr eseguito il
blocco di codice dopo la parola chiave catch (ovvero cattura, riferito appunto alleccezione).

Nellesempio abbiamo visto uneccezione generata da un errore di tipo aritmetico nel nostro codice (guardando loutput si pu
vedere che stata rilanciata dalla JVM una ArithmeticException).

Il JDK mette a disposizione una serie di classi per gestire le eccezioni, anche se, come vedremo, buona norma che quando si
sviluppa un progetto il programmatore crei la propria gerarchia (cfr. ereditariet) di eccezioni che erediti dalle eccezioni di base
definite dal JDK.

6
Il vertice della gerarchia di classi delle eccezioni Java ha la seguente struttura:

Throwable

Error Exception

RuntimeException

7
In Java Tutte le eccezioni sono classi che ereditano dalla classe Throwable.

Scendendo nella gerarchia troviamo

Error: classe che rappresenta un errore di sistema come ad esempio: memoria esaurita, limite massimo di thread allocati
per il processo etc.
Exception: classe che rappresenta un qualsiasi errore applicativo, che deve essere gestito nel codice
RuntimeException: classe figlia di Exception, rappresenta un errore applicativo del codice, gestibile dal programmatore,
ma non obbligatoriamente

Tornando allesempio, se proviamo ad aprire la JavaDoc della classe ArithmeticException, scopriremo che una classe figlia di
RuntimeException.

In Java uneccezione deve sempre essere catturata da un blocco di codice; se non provvediamo noi ad effettuare lesplicita cattura
attraverso il blocco catch, sar direttamente la JVM a catturare lerrore. Tuttavia, sempre buona norma che il programmatore
catturi leccezione nel suo codice in modo da poter personalizzare i messaggi che verranno mostrati al chiamante, magari dando
unindicazione del motivo dellerrore.

Le eccezioni che sono classi figlie di Error, come detto rappresentano degli errori nel sistema come ad esempio quando viene
esaurita la memoria RAM a disposizione, o si sta scrivendo un file su disco ed esaurito lo spazio sul disco, o si stanno aprendo

8
troppi file contemporaneamente etc.. Si tratta quindi di condizioni eccezionali che dovrebbero verificarsi abbastanza di rado nel
codice. Quando si verificano il programma deve essere terminato; il massimo che pu fare il programmatore catturare
leccezione ed inviare un messaggio che spieghi al chiamante il motivo dellerrore.

Nelle eccezioni che sono classi figlie di Exception, invece, il programmatore pu decidere di catturarle e continuare il programma
(magari inviando comunque un messaggio che chiarisca i motivi delleccezione).

Un metodo di una classe Java pu dichiarare di lanciare potenzialmente una Exception. Quando scriviamo un metodo, infatti,
possiamo sapere a priori che esistono delle condizioni in cui si verifica un errore, oppure possiamo volutamente sollevare
uneccezione se si verifica una determinata condizione.

La sintassi della firma del metodo in questi casi deve prevedere, alla fine della firma, dopo i parametri, la clausola throws seguita
dal nome della classe che rappresenta leccezione che pu essere lanciata dal nostro metodo.

Esempi:

public void metodo(String param1,int param2) throws RuntimeException

public void metodo(String param1,int param2) throws Exception

public void metodo(String param1,int param2) throws MiaException

9
Nellultimo usempio, la classe MiaException, sar una classe scritta da noi che estender Exception o RuntimeException (o una
qualunque altra classe derivate da queste).

Facciamo un esempio: immaginiamo di voler scrivere un metodo che riceva in ingresso due numeri interi e restituisca come
output il risultato della divisione intera dei due numeri:

public int divisione(int x,int y) {

int z = x / y;

Immaginiamo anche di voler controllare che il dividendo, y, non sia uguale a zero, perch non vogliamo lasciare alla JVM
lincarico di gestire leccezione, ma vogliamo rimandare un messaggio in caso sia y=0. Potremmo scrivere il metodo in questo
modo:

public int divisione(int x,int y)


{
if ( y == 0 )
{
throw new Exception("Il dividendo non pu essere uguale a zero!");
}
int z = x/y;

10
return z;
}

Tramite listruzione throw (da non confondere con throws, qui manca la s finale) il nostro metodo lancia uneccezione di tipo
Exception (ovviamente solo nel caso sia y=0).

Da notare che quando viene rilanciata leccezione con la clausola throw il flusso di codice si interrompe e non viene eseguita
listruzione z = x / y;.

A questo punto modifichiamo la firma del metodo per dichiarare che il nostro metodo pu (solo nel caso y=0) rilanciare
uneccezione:

public int divisione(int x,int y) throws Exception

Qui occorre osservare una fondamentale differenza tra le eccezioni di tipo Exception e quelle di tipo RuntimeException.

I metodi che potenzialmente rilanciano eccezioni di classe Exception devono dichiararlo nella loro firma tramite la clausola
throws; inoltre nei blocchi di codice dove vengono usati questi metodi obbligatorio catturare leventuale eccezione tramite
blocco try/catch.

Se non rispettassimo le due regole appena dette otterremmo un errore gi in fase di compilazione.

Le due regole non valgono invece per le eccezioni che sono di classe RuntimeException (e classi figlie).

11
Ad esempio nel codice mostrato prima, se non avessimo aggiunto la clausola throws nella firma del metodo divisione avremmo
avuto una segnalazione di errore in fase di compilazione del sorgente. Questo perch abbiamo deciso di rilanciare, tramite la
clausola throw, una eccezione di classe Exception.

Se modificassimo il codice dellesempio rilanciando, in caso sia y=0, uneccezione di tipo RuntimeException in luogo di
Exception potremmo anche evitare di aggiungere la clausola throws e non saremmo costretti a catturare leccezione nel codice
chiamante.

Ecco lesempio completo con la classe EsempioEccezioni2 e la classe chiamante UsoEccezione2:

package com.azienda.esempiCorso.sessione6;

public class EsempioEccezioni2


{
public int divisione(int x,int y) throws Exception
{
if ( y == 0 )
{
throw new Exception();
}
int z = x/y;
return z;
}

12
}

package com.azienda.esempiCorso.sessione6;

public class UsoEccezione2


{
public static void main(String args[])
{
try
{
EsempioEccezioni2 oggetto = new EsempioEccezioni2();
oggetto.divisione(5,0);
}
catch (Exception ex)
{
System.out.println("Eccezione catturata nella classe chiamante");
}
}
}

13
Loutput prodotto a video:

Eccezione catturata nella classe chiamante

Da notare che al blocco catch viene passato un oggetto di classe Exception. Questoggetto rappresenta leccezione che stata
sollevata dal codice che andato in errore. Se andiamo ad aprire la JavaDoc della classe Exception notiamo che esistono diversi
costruttori (overloading dei costruttori).

In particolare, esiste un costruttore al quale si pu passare un messaggio (una stringa).

E, sempre dalla JavaDoc delle API della classe Exception, vediamo che esiste un metodo che ci consente di leggere il messaggio
associato alleccezione: getMessage().

Nel nostro esempio, quando rilanciamo leccezione con la clausola throw avremmo potuto passare un messaggio alleccezione
nel seguente modo:

if ( y == 0 )
{
throw new Exception("Il dividendo non pu essere uguale a 0");
}

e nel codice del chiamante (classe UsoEccezione3) avremmo potuto recuperare il messaggio con le istruzione:

14
catch (Exception ex)
{
String message = ex.getMessage();
System.out.println("Eccezione catturata nella classe chiamante. Messaggio: " + message);
}

E loutput prodotto a video dalla classe chiamante sarebbe diventato:

Eccezione catturata nella classe chiamante. Messaggio: Il dividendo non pu essere uguale a 0

Sempre guardando le API della classe Exception attraverso la JavaDoc possiamo vedere che esiste anche un altro costruttore
della classe al quale si pu passare come parametro un oggetto di classe Throwable e che rappresenta leccezione originaria.

Infatti, in Java si pu creare una catena di eccezioni.

Ad esempio, avremmo potuto modificare il nostro codice desempio provando ad eseguire listruzione x/y senza controllare prima
se y=0; avremmo potuto farlo allinterno di un blocco try / catch, in modo che se la divisione andava in errore avremmo catturato
leccezione ArithmeticException lanciata dalla JVM e avremmo potuto rilanciare una nuova RuntimeException specificando
come parametro leccezione originale di classe ArithmeticException.

A questo punto avremmo potuto modificare il codice chiamante in modo da recuperare anche leccezione originale tramite il
metodo getCause().

15
package com.azienda.progettoCorso.examples.exception;

public class EsempioEccezioni4


{
public int divisione(int x,int y) throws Exception
{
int z = 0;
try
{
z = x/y;
}
catch (ArithmeticException ex)
{
throw new RuntimeException("Il dividendo non pu essere uguale a 0",ex);
}
return z;
}
}

package com.azienda.progettoCorso.examples.exception;

public class UsoEccezioni4


{
public static void main(String args[])

16
{
try
{
EsempioEccezioni4 oggetto = new EsempioEccezioni4();
oggetto.divisione(5,0);
}
catch (Exception ex)
{
String message = ex.getMessage();
Throwable throwable = ex.getCause();
System.out.println("Eccezione catturata nella classe chiamante.\nMessaggio: " + message + "\nEeccezione
originale: " +
throwable);
}
}
}

Output a video:

Eccezione catturata nella classe chiamante.


Messaggio: Il dividendo non pu essere uguale a 0
Eeccezione originale: java.lang.ArithmeticException: / by zero

17
Eccezioni personalizzate

Come anticipato prima molto commune, ed una buona pratica (in gergo best practice), che allinterno di un progetto si
definiscano delle classi ad-hoc per identificare le eccezioni specifiche del progetto. Questo concetto lo vedremo applicato nella
pratica pi avanti quando introdurremmo il progetto di esempio che svilupperemo e che ci accompagner in tutto il corso.

Si tratter, in pratica, di creare delle classi (eventualmente una gerarchia di classi) che estenderanno Exception per le eccezioni
che vogliamo siano obbligatoriamente catturate dal codice chiamante e/o una gerarchia di classi figlie di RuntimeException per le
eccezioni che riteniamo non sia obbligatorio catturare nel codice chiamante

Con questa sessione termina la parte, un po pi teorica, del corso relativa alle basi del linguaggio Java. Le successive sessioni
diventano progressivamente sempre pi di carattere pratico, maggiormente basate sullillustrazione del codice sorgente (pertanto
sempre molta attenzione alle relative sessioni video) e di esempi applicativi.

18

Вам также может понравиться