La gestione delle eccezioni
Linguaggi Java
La gestione delle eccezioni
Le eccezioni sono eventi che accadono in fase di esecuzione di un programma al verificarsi
di una situazione anomala, come la divisione per 0, l'uso di un indice per un vettore con
valore superiore a quello massimo, ….
Al verificarsi di una condizione anomala abbiamo due possibilità:
1. lasciare che il programma termini la sua esecuzione in maniera anomala
2. intercettarla e gestirla
La prima soluzione è quella più comoda e che non ci comporta alcun aggravio nella
scrittura del codice, però in alcuni casi si potrebbero cerare delle incongruenze, come ad
esempio nel caso di connessioni a database o in caso di avere degli aggiornamenti a metà.
E' preferibile dunque la seconda opportunità, che ci permette di intercettare il verificarsi di
una condizione anomala e di compiere in tal caso delle azioni di vario tipo tipo, anche solo
dare un diagnostico comprensibile all'utente, prima di terminare l'esecuzione.
Le cause che possono portare ad un'eccezione sono molte e vengono raggruppate a
seconda del loro tipo. Le principali sono
 errori software compiuti dal programmatore
 input errato dovuto alla digitazione dell'utente
 violazione sicurezza come la richiesta di accedere ad un file senza i diritti
 indisponibilità di risorse sia hardware ch software (es file)
Quando si verifica un'eccezione non gestita a programma interviene la JVM che interrompe
l'esecuzione del programma e h
genera un messaggio chiamato stack-trace, che riporta oltre al tipo di eccezione
intercettata, anche il metodo che l'ha provocata, a quale linea di codice e la catena di
invocazione di metodi precedenti all'errore intercettato.
NB: anche se al verificarsi di un'eccezione non è possibile continuare l'esecuzione come se
nulla fosse accaduto, può essere importante in caso di errore eseguire delle operazioni
prima di chiudere il programma, come ad esempio se si ha aperto un file, una connessione
di rete o a un fatabase.
Per permettere la gestione degli errori, Java mette a disposizione delle classi tutte derivate
dalla classe java.lang.Exception che a sua volta deriva dalla classe java.lang.Throwable.
L'intercettazione degli errori avviene tramite un costrutto di programmazione che tende
una trappola agli errori:
try
{
…...
…...
}
catch (Throwable tr) {
System.out.println(“errore “ + tr.toString());
}
Nel caso in cui le istruzioni presenti nel “blocco di caccia” provocano un errore del tipo
indicato dopo la parola chiave catch (nell'esempio Throwable) nel blocco dii istruzioni
immediatamente successivo e delimitato da { }, il programmatore può indicare le istruzioni
da compiere prima del termine del programma.
Fondazione ITS A. Volta – Linguaggi -Java – Flavia Lollis
1
Linguaggi Java
Java prevede l’intercettazione di molti tipi dio errori, da cui è stata creata una gerarchia
delle classi in base alla tipologia di errore; le principali sono
Esistono dunque molte classi di errori intercettabili, e di conseguenza Java permette di
intercettarle tutte, eseguendo anche per ognuna delle azioni diverse semplicemente
utilizzando dopo il blocco try più blocchi catch, uno per ogni errore che si vuole
intercettare
try
{
}
catch (IOException ex)
{
….......
}
catch (Throwable tr)
{
….......
}
In alcuni casi Java ci obbliga a gestire alcune eccezioni, come ad esempio nel caso di
trattamento dell’I/O.
Fondazione ITS A. Volta – Linguaggi -Java – Flavia Lollis
2
Linguaggi Java
Per le operazioni di input esiste un oggetto predefinito della classe System associato
all’input, chiamato System.in che è un oggetto di tipo InputStream, che però tratta solo un
carattere alla volta.
Per leggere una riga intera bisogna fare ricorso al metodo readLine() della classe
BufferedReader, che legge l’intera riga digitata e ce la restituisce nel formato String.
Il costruttore della classe BufferedReader ha bisogno come parametro di input per creare
l’oggetto che ci serve, un InputStreamReader, che dobbiamo creare collegato alla tastiera
per poi passarglielo.
Ci serve una InputStreamReader che si appoggi System.in per colloquiare con l’esterno,
pertanto scriveremo:
//* creiamo un’istanza di InputStreamReader, il cui costruttore si aspetta in input un
oggetto di tipo InputStream, passandogli System.in che è proprio una InputStream
InputStreamReader leggi = new InputStreamReader(System.in);
//* ora utilizziamo l’oggetto appena istanziato per creare un’istanza di BufferedReader
BufferedReader input = new BufferedReader(leggi);
//* con la seguente istruzione avrò disponibile nella variabile linea di tipo String, quanto
digitato da tastiera
String linea = input.readLine();
NB- il metodo readLine() specifica che si potrebbe verificare un errore di tipo IOException,
e che quindi la parte di codice che usa questo metodo deve tenerne conto. Per questo è
necessario indicare in quale parte di codice può accadere e cosa fare in caso di errore. Cò
lo si fa con
try
{
…..
input.readLine();
…..
} catch(IOException ex)
{
System.err.println("errore " + ex.toString());
}
Fondazione ITS A. Volta – Linguaggi -Java – Flavia Lollis
3
Linguaggi Java
Se poi vorremo leggere da tastiera un numero, i basterà trasformare la stringa letta in un
numero utilizzando l’apposita classe in base al tipo di dato che ci serve:
int num_int = Integer.parseInt(input.readLine());
float num_f = Float.parseFloat(input.readLine());
double num_d = Double.parseDouble(input.readLine());
Parola chiave throws
Quando si intercetta un errore si deve anche esplicitare le azioni da compiere al verificarsi
dell’errore trattato; può però accadere che il metodo nel quale si intercetta l’errore non
abbia conoscenze sufficienti per poter trattare l’errore in modo adeguato, e che queste
conoscenze siano patrimonio del metodo chiamante.
In questo caso deve essere il chiamante a trattare l’errore, però il metodo che rileva
l’errore deve dichiarare tramite la parola chiave throws che le sue istruzioni potrebbero
sollevare un’eccezione: così chi lo chiama sa che dovrà chiamare il metodo in un blocco try
catch.
Facciamo l’esempio di un programma che legge orario di entrata e di uscita controllando la
validità dei dati digitati:
import java.io.*;
public class ProvaThrow {
int orae,mine,orau,minu;
public static void main(String[] args){
new ProvaThrow();
}
public ProvaThrow(){
try
{
leggiDati();
} catch (IOException ioe) { System.out.println(ioe);}
}
public void leggiDati() throws IOException
{
BufferedReader inp= new BufferedReader (new InputStreamReader(System.in));
System.out.println("digita ora entrata ");
int orae=Integer.parseInt(inp.readLine());
System.out.println("digita min entrata");
int mine=Integer.parseInt(inp.readLine());
System.out.println("digita ora uscita ");
int orau=Integer.parseInt(inp.readLine());
System.out.println("digita min uscita");
int minu=Integer.parseInt(inp.readLine());}}
Fondazione ITS A. Volta – Linguaggi -Java – Flavia Lollis
4
Linguaggi Java
Questo modo di scrivere è del tutto equivalente a scrivere
import java.io.*;
public class ProvaThrow {
int orae,mine,orau,minu;
public static void main(String[] args){
new ProvaThrow();
}
public ProvaThrow(){
leggiDati();
}
public void leggiDati()
try
{
{
BufferedReader inp= new BufferedReader (new InputStreamReader(System.in));
System.out.println("digita ora entrata ");
int orae=Integer.parseInt(inp.readLine());
System.out.println("digita min entrata");
int mine=Integer.parseInt(inp.readLine());
System.out.println("digita ora uscita ");
int orau=Integer.parseInt(inp.readLine());
System.out.println("digita min uscita");
int minu=Integer.parseInt(inp.readLine());
} catch (IOException ioe) { System.out.println(ioe);}
}}
Definizione e generazione di una nuova eccezione
Il linguaggio Java, grazie al concetto di ereditarietà, ci consente facilmente di creare delle
nuove classi di errore semplicemente estendendo la classe Exception.
Ad esempio se in un metodo dobbiamo controllare che i due interi in input rappresentino
ora e minuti validi come orario, possiamo creare una nuova classe OrarioErrato da
utilizzare nelle nostre classi per descrivere questa nuova tipologia di errore:
public class OrarioErrato extends Exception {
String motivo;
public OrarioErrato(String xx){
motivo=xx;
}
}
In questo modo, ogni volta che si rileva un errore applicativo di questo tipo, lo si può
trattare come un’eccezione utilizzando le parole chiave throws e throw: la prima, come
si è visto nel paragrafo precedente, per indicare che un certo metodo potrebbe rilevare
Fondazione ITS A. Volta – Linguaggi -Java – Flavia Lollis
5
Linguaggi Java
l’eccezione ed avvisare così gli utilizzatori che devono gestirlo, la seconda per provocare
l’eccezione se si verificano le condizioni adatte.
Per chiarire il tutto vediamo l’esempio di un programma che legge oora e minuti di entrata
ed uscita, calcola il numero di secondi di permanenza controllando anche la correttezza dei
dati digitati:
import java.io.*;
public class ProvaThrow {
int orae,mine,orau,minu;
public static void main(String[] args){
new ProvaThrow();
}
public ProvaThrow(){
try
{
leggiDati();
try
{
int diff=calcDiff(orae, mine, orau, minu);
} catch (OrarioErrato oe) {System.out.println (oe.motivo+ "
prossima volta digita meglio");}
} catch (IOException ioe) { System.out.println(ioe);}
}
public void leggiDati() throws IOException{
InputStreamReader(System.in));
BufferedReader inp= new BufferedReader (new
System.out.println("digita ora entrata ");
int orae=Integer.parseInt(inp.readLine());
System.out.println("digita min entrata");
int mine=Integer.parseInt(inp.readLine());
}
public int calcDiff(int oe, int me, int ou, int mu) throws OrarioErrato {
int d,sec1, sec2;
if (!orarioOK(oe,me) )
{
throw new OrarioErrato("orario entrata errato");
}
else
{
if (!orarioOK(ou,mu) )
{
throw new OrarioErrato("orario uscita errato");
}
else
{
Fondazione ITS A. Volta – Linguaggi -Java – Flavia Lollis
6
la
Linguaggi Java
}
sec1=oe*3600+me*60;
sec2=ou*3600+mu*60;
return (sec2-sec1);
}
}
public static boolean orarioOK(int hh, int mm){
if (hh>=0 && hh<=24 && mm>=0 && mm<=60)
{
return true;
} else
{
return false;
}
}
}
Fondazione ITS A. Volta – Linguaggi -Java – Flavia Lollis
7