1. Introduzione
Nella programmazione spesso ci sono situazioni in cui un metodo incontra un errore ma non sa come gestirlo correttamente. Per esempio, un metodo legge un file ma non sa cosa fare se il file non c’è: chiedere all’utente? Terminare il programma? Provare un altro file? In tali casi il metodo può «spostare la responsabilità» a chi lo ha chiamato — cioè «propagare» l’eccezione lungo la catena delle chiamate.
Propagazione dell’eccezione — è un meccanismo che permette a un metodo di non gestire l’errore in autonomia, ma di informare il codice chiamante: «Ho un problema, occupatene tu!»
Analogia: Immagina di essere un operatore di call center. Ti chiama un cliente con una domanda a cui non sai rispondere. Invece di indovinare, dici: «Un attimo, la metto in contatto con uno specialista». Stai «propagando» la domanda più avanti.
Parola chiave throws: come funziona
In Java per propagare le eccezioni si usa la parola chiave throws nella dichiarazione del metodo.
Sintassi:
tip_vozvrashchaemogo_znacheniya imyaMetoda(...) throws ExceptionType
{
// codice del metodo
}
Dopo throws si indica il tipo di eccezione che può verificarsi in questo metodo. È come un avviso per altri programmatori: «Attenzione! Questo metodo può lanciare un’eccezione di un certo tipo. Siate pronti!»
Esempio:
public void readFile(String filename) throws FileNotFoundException
{
FileReader reader = new FileReader(filename); // può lanciare FileNotFoundException
// ...
}
Qui il metodo readFile non gestisce l’errore da solo, ma comunica: «Posso lanciare FileNotFoundException — che sia chi mi ha chiamato a decidere cosa fare».
2. Come dovrebbe reagire il metodo chiamante?
Se chiami un metodo dichiarato con throws, hai due opzioni:
- Gestire l’eccezione con try-catch
- Propagare l’eccezione più avanti (aggiungere throws al tuo metodo)
Opzione 1: gestire con try-catch
public static void main(String[] args)
{
try
{
readFile("data.txt");
}
catch (FileNotFoundException e)
{
System.out.println("File non trovato: " + e.getMessage());
}
}
Qui catturiamo l’eccezione e decidiamo noi cosa fare (per esempio, mostriamo un messaggio all’utente).
Opzione 2: propagare più avanti
public static void main(String[] args) throws FileNotFoundException
{
readFile("data.txt");
}
Ora la responsabilità della gestione dell’errore ricade su chi chiamerà main (di solito è la stessa JVM — se l’errore non viene gestito, il programma terminerà con un messaggio di errore).
3. Esempio: lettura di un file con propagazione dell’eccezione
Esempio completo con IOException e gestione a livello di main:
import java.io.*;
public class FileDemo
{
// Il metodo dichiara che può lanciare IOException
public static void printFirstLine(String filename) throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line = reader.readLine();
System.out.println("Prima riga: " + line);
reader.close();
}
public static void main(String[] args)
{
try
{
printFirstLine("nofile.txt");
}
catch (IOException e)
{
System.out.println("Errore durante la lettura del file: " + e.getMessage());
}
}
}
Il metodo printFirstLine non sa cosa fare se il file non c’è — semplicemente propaga l’eccezione. In main catturiamo l’errore e stampiamo un messaggio.
4. Dettagli utili
Quando e perché usare la propagazione delle eccezioni?
- Quando un metodo non può o non deve decidere come gestire l’errore (per esempio, codice di libreria).
- Quando la gestione dell’errore dipende dal contesto (in un caso terminare il programma, in un altro — provare un altro file).
- Per non appesantire il codice con try-catch superflui dove non servono.
Best practice: propagate le eccezioni se non potete gestirle in modo sensato. Non catturate eccezioni solo per pro forma!
Si possono propagare più eccezioni
public void process() throws IOException, SQLException
{
// ...
}
Eccezioni checked e unchecked: promemoria
Checked exceptions (per esempio, IOException, SQLException) — il compilatore richiede che siano gestite o propagate.
Unchecked exceptions (per esempio, NullPointerException, IllegalArgumentException) — il compilatore non richiede la gestione; non è necessario indicarle in throws.
5. Errori tipici nella propagazione delle eccezioni
Errore n. 1: avete dimenticato di dichiarare throws per un’eccezione checked.
Se un metodo può lanciare un’eccezione checked, ma non la dichiari in throws e non la gestisci tramite try-catch, il compilatore segnalerà un errore.
Errore n. 2: catturate l’eccezione ma non la gestite.
Scrivere catch (Exception e) {} — è una cattiva pratica! Meglio propagare l’eccezione più avanti se non sapete cosa farne.
Errore n. 3: propagate un tipo troppo generico.
Se il metodo può lanciare solo FileNotFoundException, non scrivete throws Exception — rende più difficile capire il codice.
Errore n. 4: indicate eccezioni unchecked in throws.
Non ha senso scrivere throws NullPointerException — il compilatore non lo richiede e non aiuta la gestione degli errori.
GO TO FULL VERSION