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:

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:

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:

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:

// 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);
	}
}

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;
}