11. Gestione delle eccezioni
Una procedura può finire in due modi: termina normalmente oppure si verifica un’eccezione durante la sua esecuzione.
Un’eccezione è un oggetto speciale ritornato da un metodo:
- Le eccezioni sono riportate al chiamante, che deve poi gestirle
- Le eccezioni hanno un tipo (classe)
- Le eccezioni possono contenere dati che possono far capire che cosa le ha fatte verificare
- Le eccezioni possono anche essere definite dall’utente
Blocco try/catch
Un’eccezione deve essere catturata e gestita mediante il blocco try/catch
.
Ex.
try{
x = x/y;
} catch (DivisionByZeroException e){
System.out.println("Hai cercato di dividere per 0");
}
È anche possibile mettere più blocchi catch
in sequenza.
try{...} catch{...} catch{...}
Propagazione degli errori
L’esecuzione di un blocco dove si verifica un’eccezione viene terminata.
Se nel blocco corrente c’è un blocco try/catch
che è in grado di gestire l’eccezione, il controllo viene passato al ramo che gestisce l’eccezione e poi al blocco successivo.
In caso contrario, si inizia a lanciare l’eccezione verso l’alto, cercando un blocco in grado di gestire l’eccezione: se non si trova, si termina il blocco o il metodo e si continua a salire.
Se non viene trovato NESSUN blocco che gestisce l’eccezione, il programma viene ucciso.
Il blocco finally
Viene messo dopo il blocco try/catch
e viene sempre eseguito, anche se si verifica un’eccezione.
Metodi con eccezioni
Se un metodo può lanciare eccezioni, dobbiamo segnalarlo:
public int leggiIntero() throws IOException;
Lanciare un’eccezione
public int fact(int n) throws NegativeException{
if(n<0) throw new NegativeException(); // Lancio l'eccezione
//...
}
Eccezioni Checked
Devono essere dichiarate dai metodi che le possono lanciare (sennò si incorre in errori di compilazione).
Ex. Quando un metodo M1 chiama un metodo M2 che può lanciare un’eccezione checked EX, allora deve essere vera almeno una delle due seguenti condizioni:
- L’invocazione di M2 avviene dentro un blocco
try/catch
di M1 che è in grado di gestire EX
- Il tipo di eccezione di EX è dichiarato nella clausola
throws
di M1
Eccezioni Unchecked
Possono essere propagate senza che esse siano dichiarate nell’header del metodo e possono anche non essere necessariamente gestite da un blocco try/catch
.
Conviene sempre includerle nella clausola throws
al momento della dichiarazione di un metodo.
Il loro uso dovrebbe essere limitato a casi in cui:
- Queste eccezioni sono eccezioni che derivano da operazioni aritmetiche / logiche
- C’è un modo conveniente e poco costoso per gestirle
- L’ eccezione è usata in un contesto ristretto
Definizione di nuove eccezioni
Gli oggetti definiti dall’utente possono essere usati per lanciare eccezioni e propagarle se il tipo T è un sottotipo di una tra le classe Exception
o RuntimeException
.
La classe che definisce la nuova eccezione non è diversa da quelle che definiscono oggetti creati dall’utente:
- può avere attributi e metodi propri, usati per fornire informazioni aggiuntive all’exception handler.
// Eccezione checked:
public class NewKindOfException extends Exception {
public NewKindOfException(){ super();}
public NewKindOfException(String s){ super(s);}
}
// Eccezione unchecked:
public class NewKindOfException extends RuntimeException{
public NewKindOfException(String errorMessage, Throwable err){
super(errorMessage, err);
}
}
- Il tipo di EX è parte di eccezioni dichiarate nella clausola
throws
Masking
Consiste nel far proseguire la normale esecuzione di un programma, dopo la cattura di un’eccezione: l’eccezione viene gestita e non viene propagata al chiamante.
In questo caso possono rientrare eccezioni usate per verificate determinate condizioni.
public static boolean sorted (int[] a){
int prev;
try { prev = a[0];} // Lancia un'eccezione se l'array è vuoto
catch(IndexOutOfBoundsException e){ return true; }
for (int i = 1; i < a.lenght; i++){
if (prev <= a[i])
prev = a[i];
else
return false;
}
return true;
}