Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena...

30
Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dell’Informazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 [email protected] www.dii.unisi.it/ ~ rigutini /

Transcript of Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena...

Page 1: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Eccezioni

Dott. Ing. Leonardo RigutiniDipartimento Ingegneria dell’InformazioneUniversità di SienaVia Roma 56 – 53100 – SIENAUff. [email protected]/~rigutini/

Page 2: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Eccezioni

Page 3: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Gestione errori

Un fallimento nel programma può avere diverse cause: Dati errati in ingresso Errori di programmazione Ecc …

Due aspetti nella gestione dei fallimenti: Individuazione : rilevare un fallimento Ripristino : ripristinare il programma in modo che possa continuare

(gestire l’errore)

Il problema maggiore nella gestione degli errori è che solitamente il punto in cui viene individuato l’errore non è accoppiato al punto di ripristino, cioè il punto dove viene gestito l’errore

Page 4: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Gestione errori

Per esempio: se nella classe Integer utilizziamo il metodo parseInt per trasformare una

String in un int, ma la stringa che attualmente stiamo esaminando non rappresenta un numero (es. “pippo”), abbiamo un errore (a run-time) ma il metodo parseInt non è in grado di decidere cosa fare: chiedere all’utente ? Terminare bruscamente il programma ?

Il più delle volte quindi, l’errore verificatosi dentro un metodo deve essere riportato all’esterno del metodo stesso: Ritornando un valore particolare (per esempio false , -1) Lanciando una ecezione

Page 5: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Ritorno di un valore particolare E’ possibile notificare l’avvento di un errore dentro una funzione

facendo in modo che tale funzione ritorni un valore se tutto viene eseguito in maniera corretta, un altro altrimenti: Es.

il metodo drive(int km) di Auto, ritorna 0 se è finita la benzina, > 0 altrimenti.

I problemi di questo approccio : diventa necessario ogni volta controllare i valori di ritorno delle funzioni per

verificare se sono occorsi errori o meno. In ogni funzione è necessario controllare che ogni istruzione (o quasi) sia

eseguita in maniera corretta

Inoltre ritornando un tipo di dato semplice (int o boolean) nessuna informazione può essere estratta dall’errore: La cosa da fare sarebbe di creare una classe apposita che sia ritornata da

ogni metodo e che memorizzi le informazioni sugli errori

Page 6: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Lanciare un eccezione

L’alternativa all’uso di valori di ritorno delle funzioni, è di lanciare particolari eventi che segnalano in maniera asincrona il verificarsi dell’errore: Le eccezioni

Le eccezioni sono classi particolari di Java che memorizzano l’errore e vengono lanciate e catturate all’interno del programma: Lanciare un eccezione quando avviene un errore Catturare l’eccezione per gestire l’errore

Per lanciare una eccezione si usa la parola riservata throw

Page 7: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Eccezioni Il java fornisce una serie di classi built-in per gestire le eccezioni,

tutte derivate dalla classe Exception:

Exception

IOException

UnknownHostException

MalformedURLException

FileNotFoundException

EOFException

ClassNotFoundException

CloneNotSupportedException

RuntimeException

AritmeticException

ClassCastException

NullPointerException

Page 8: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Es.

Supponiamo di progettare la funzione drive() della classe Auto in modo che notifichi il fatto che vogliamo percorrere più km di quanti ne possiamo fare con la benzina rimasta nel serbatoio

class Auto {//public void drive(double km) {

double c= km/consumo;if (c > carburante) throw new Exception(“Not enough gas”);carburante=-c;

}

}

Lancia una eccezione generica Exception

Page 9: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Eccezioni

In alternativa è possibile ovviamente derivare classi per le eccezioni che riguardano il nostro progetto

Per esempio noGasException:

class noGasException extends Exception {}

class Auto {//public void drive(double km) {

double c= km/consumo;if (c > carburante)

throw new noGasException (“Not enough gas”);carburante=-c;

}

}

Page 10: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Oggetti Exception

Essendo una classe, ogni eccezione può essere memorizzata in una variabile oggetto:

class noGasException extends Exception {}

class Auto {//public void drive(double km) {

double c= km/consumo;noGasException E;if (c > carburante) {

E=new noGasException (“Not more gas”);carburante=0;throw E;}

carburante=-c;

}}

variabile E memorizzaun oggetto eccezione di tipo noGasException

Page 11: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Classe Error

Esiste una seconda categoria di errori interni che vengono segnalati lanciando oggetti di tipo Error.

Questi errori sono errori fatali che accadono di rado e non sono controllabili dal programmatore. Ad esempio l’errore OutOfMemoryError, che viene lanciato quando non vi è più memoria disponibile.

Tali situazioni non sono gestibili dal programmatore

Page 12: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Lanciare una eccezione

Quando viene lanciata una eccezione, il metodo termina immediatamente la propria esecuzione, come se fosse stato eseguito un return . L’esecuzione non procede nel metodo che aveva invocato quella funzione, ma nel gestore dell’eccezione.

E’ buona regola non abusare del lancio di eccezioni: consideriamo la funzione readLine della classe BufferedReader. Questa funzione legge una riga (fino a \n) da un input stream. Questa funzione non ritorna una eccezione di tipo EOFException quando arriva in fondo allo stream. Perché?

La risposta è che terminare lo stream non è una cosa eccezionale, cioè se si legge un file, è ovvio che prima o poi si arriva alla fine del file e quindi trovare EOF non è da considerarsi errore

Page 13: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Eccezioni controllate e non-controllate Le eccezioni Java rientrano in due categorie, chiamate eccezioni

controllate e non controllate

Eccezioni controllate – quando chiamate un metodo che lancia una eccezione controllata, dovete specificare come gestire l’eccezione nel caso essa venga lanciata. Ad esempio tutte le eccezioni IOException sono eccezioni controllate.

Eccezioni non controllate – il compilatore non richiede che teniate traccia delle eccezioni non controllate come NullPointerException, NumberFormateException ecc …

Più in generale tutte le eccezioni che appartengono alle sottoclassi di RuntimeException sono eccezioni non controllate, mentre tutte la altre sottoclassi di Exception sono controllate.

Page 14: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Eccezioni controllate e non controllate Perché ci sono due tipi di eccezioni?

Un eccezione controllata descrive un problema che prima o poi può accadere, indipendentemente da quanto sia stato scritto bene il codice

Le eccezioni non controllate, invece, rappresentano un errore in programmazione. Quindi diventa inutile forzare la gestione di una eccezione di questo tipo, poiché nel caso si verifichi, è necessario modificare il codice.

Ad esempio: La fine inattesa di un file (EOFException) non dipende da cause che

sono sotto il nostro controllo (errore sul disco o errore di rete) e quindi si è forzati a prevedere una routine di gestione di tali situazioni

Un nullPointerException, invece, segnala un accesso ad una variabile non inizializzata (null) e quindi un errore nel codice che cerca di utilizzare un riferimento null. Il compilatore non verifica che gestiate un nullPointerException poiché dovreste scrivere codice che eviti l’accesso a riferimenti null

Page 15: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Eccezioni controllate e non controllate In realtà queste categorie non sono perfette:

non è colpa del programmatore se un utente inserisce un numero non corretto, ma l’eccezione NumberFormatException, lanciata da Integer.parseInt(String) è un eccezione non controllata

Vedrete che la maggior parte delle eccezioni controllate accodono nella gestione dei dati in ingresso o in uscita, che è un fertile terreno per guasti esterni che non dipendono dal codice: Un file può essere stato rimosso o corretto La rete può essere disattivata Un server può essere non disponibile Ecc …

Page 16: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Eccezioni controllate

Quando viene utilizzato un metodo che lancia una eccezione controllata, è necessario specificare cosa fare: Rimandare la gestione della eccezione al metodo chiamante Catturare l’eccezione e gestirla in locale

Rimandare l’eccezione al chiamante – se stiamo implementando un metodo in cui viene lanciata una eccezione controllata (o che utilizza un metodo che lancia una eccezione controllata) e non siamo in grado di gestirla, tale eccezione viene passata direttamente al metodo chiamante. Questa operazione viene fatta post-ponendo alla dichiarazione del metodo che stiamo implementando la parola di codice throws

Page 17: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Rimandare l’eccezione al chiamante Es

class noGasException extends Exception {}

class Auto {//public void drive(double km) throws noGasException {

double c= km/consumo;if (c > carburante) {

carburante = 0;throw new noGasException (“Not enough gas”);}

carburante=-c;}

}

Ogni metodo che chiamadrive() deve gestire l’eccezionedi tipo noGasException

Page 18: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Rimandare l’eccezione al chiamanteclass Auto {

public int checkGas() throws noGasException {if (carburante <=0 ) {

throw new noGasException (“Not more gas”);}

return carburante;}//public void drive(double km) throws noGasException {

double c= km/consumo;if (checkGas()) {

carburante = 0;}

carburante=-c;}

}

Il metodo checkGas lanciaun eccezione noGasException e deve essere gestita in drive(): drive rimanda la gestione alla funzione che chiamerà drive()

Page 19: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Rimandare l’eccezione al chiamante Quando un metodo rimanda più eccezioni controllate, vanno

elencate dopo throws separate con virgole:

public void drive(double km) throws IOException, noGasException {

…checkGas() <- lancia noGasExceptionreadFile() <- lancia IOException…

}

Page 20: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Rimandare l’eccezione al chiamante Ovviamente se viene fatto un throws di un tipo di eccezione, tutte i

tipi di eccezioni figli sono compresi:

public void drive(double km) throws Exception {…checkGas() <- lancia noGasExceptionreadFile() <- lancia IOException

…}

Tutte le eccezioni Sono prese da throws Exception

Page 21: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Catturare le eccezioni

Una eccezione prima o poi dovrà essere gestita. Normalmente accade che le eccezioni vengono lanciate in classi di basso livello e gestite nelle classi di alto livello, dove si ha una conoscenza dell’ambiente maggiore

Per gestire una eccezione è necessario catturarla ed implementare il codice che deve essere eseguito una volta catturata.

Se devono essere gestite due eccezioni, è necessario specificare il codice per ogni tipo di eccezione che viene catturata oppure catturare una eccezione padre di entrambe (ereditarietà).

Page 22: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Catturare le eccezioni

Per catturare le eccezioni si usa il costrutto:try {

linee di codice del programma}

catch (eccezione_tipo1 E1) { linee di codice per la gestione dell’eccezione E1}

catch (eccezione_tipo2 E2) { linee di codice per la gestione dell’eccezione E2}

Le istruzioni contenute nel blocco di codice delimitato da try { e } sono eseguite come normale linee di codice. Appena avviene in esse una eccezione (generata localmente o derivante da qualche funzione interna al try ) , il controllo viene passato al ramo catch() relativo e vengono eseguite le istruzioni delimitate da { }

Page 23: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Catturare le eccezioniclass Auto {

public int drive(double km) throws noGasException {double c= km/consumo;if (carburante <= c ) {

carburante = 0;throw new noGasException (“No more gas”);}

carburante=-c;return carburante;

}}class Autodromo {

public void run() {Auto Ferrari=new Auto();try {

Ferrari.drive(200);Ferrari.stop();

}catch (noGasException E) {

System.err.println(“E’ finita la benzina!!”);}

}}

La clausola throws noGasException non è più necessaria, poiché l’eccezione è gestita localmente nel try - catch

Se il metodo drive lancia un eccezione noGasException essa viene catturata dal catch

Page 24: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Informazioni sulle eccezioni

La classe Exception di Java prevede una serie di funzioni utiliìssime in caso di debug. Ha la possibilità di memorizzare un messaggio in fase di lancio della

eccezione (nel costruttore). printStackTrace() – stampa lo stack della CPU al momento della

eccezione (lista di funzioni attualmente nello stack di sistema) getMessage() – stampa il messaggio memorizzato dentro l’eccezione.

E’ consigliato gestire sempre in maniera esplicita le eccezioni, eventualmente stampando sullo stdout il messaggio e lo sack: non mettere a tacere le eccezioni per nessun motivo, poiché se si

verifica un errore non ce ne accorgiamo

Page 25: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Catturare le eccezioniclass Auto {

public int drive(double km) throws noGasException {double c= km/consumo;if (carburante <= c ) {

carburante = 0;throw new noGasException (“Not more gas”);}

carburante=-c;return carburante;

}}class Autodromo {

public void run() {Auto Ferrari=new Auto();try {

Ferrari.drive(200);Ferrari.stop();

}catch (noGasException E) {}

}}

Come sappiamo che è avvenuta una eccezione??

Page 26: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Catturare le eccezioniclass Auto {

public int drive(double km) throws noGasException {double c= km/consumo;if (carburante <= c ) {

carburante = 0;throw new noGasException (“Not more gas”);}

carburante=-c;return carburante;

}}class Autodromo {

public void run() {Auto Ferrari=new Auto();try {

Ferrari.drive(200);Ferrari.stop();

}catch (noGasException E) {

E.printStackTrace();}

}}

Stampa lo stack della applicazione sullo stderr.Notare l’uso della variabile noGasException E e la chiamata ad un metodo ereditato da Exception

Page 27: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

La clausola finally

A volte si ha bisogno di eseguire comunque delle istruzioni prima di lasciare il comando al gestore delle eccezioni.

Il costrutto finally { } permette di specificare una serie di istruzioni che devono essere eseguite comunque sia che non si verifichi nessuna eccezione, sia che si sia verificata una eccezione.

Un esempio classico è la chiusura di un file: se abbiamo aperto un file e si verifica una eccezione (una delle tante che possono essere catturate), è necessario chiudere il file prima di gestire l’eccezione.

Page 28: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

La clausola finallyclass Auto {

public int drive(double km) throws noGasException {double c= km/consumo;if (carburante <= c ) {

carburante = 0;throw new noGasException (“Not more gas”);}

carburante=-c;return carburante;

}}class Autodromo {

public void run() {Auto Ferrari=new Auto();try {

Ferrari.drive(200);Ferrari.stop();

}finally {

System.out.println(“Ferrari ciao!”);}

}}

La stampa di “Ferrari ciao!!” viene sempre eseguita, sia che avvenga l’eccezione sia che non avvenga.

Page 29: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Note di cronaca

Il 4 giugno 1996, il razzo Arianne sviluppato dall’ESA virò dalla sua rotta dopo circa 40 secondi dal lancio e dovette essere distrutto in volo per evitare pericoli

La causa che innescò questo incidente fu un eccezione non gestita! Il missile conteneva due sensori (uno di riserva) che elaboravano dati e li trasformavano in informazioni riguardanti la posizione del missile.

Uno dei sensori misurò una forza di accelerazione maggiore e tale valore espresso in virgola mobile doveva essere memorizzato in un intero a 16 bit.

Il linguaggio ADA, utilizzato nei dispositivi, genera una eccezione nel caso di simili cast ma i programmatori avevano deciso che tale situazione non sarebbe mai accaduta e non avevano gestito l’eccezione

Page 30: Eccezioni Dott. Ing. Leonardo Rigutini Dipartimento Ingegneria dellInformazione Università di Siena Via Roma 56 – 53100 – SIENA Uff. 0577233606 rigutini@dii.unisi.it.

Note di cronaca

Quando avvenne il trabocco, venne lanciata l’eccezione e poiché non c’era il gestore, il sensore si spense.

Il computer allora attivò il sensore di riserva, che lanciò la stessa eccezione e si spense anche lui.

I progettisti non avevano previsto che due sensori si spegnessero insieme dato che le probabilità di un simile evento sono remotissime.

A quel punto il razzo era privo delle informazioni sulla propria posizione e sulla rotta.

… BUM !!