- 1 1. Introduzione: Perché “try” è importante in Java
- 2 2. Le basi di try: sintassi e funzionamento
- 3 3. Come Usare catch, finally, throw e throws
- 4 4. Pattern Avanzati: try-with-resources e Propagazione delle Eccezioni
- 5 Propagazione delle Eccezioni: Come le Eccezioni Si Spostano Verso Metodi di Livello Superiore
- 6 5. Errori Comuni, Anti‑Pattern e Come Correggerli
- 6.1 1. Il Blocco try è Troppo Grande
- 6.2 2. Lasciare il catch vuoto (Inghiottire l’eccezione)
- 6.3 3. Catturare eccezioni con un tipo troppo generico
- 6.4 4. Lanciare un’eccezione all’interno di finally
- 6.5 5. Dimenticare di chiamare close()
- 6.6 6. Pensare “Dovrei lanciare tutto con throws”
- 6.7 Principi fondamentali per prevenire gli anti‑pattern
- 7 6. Esempi di codice pratici: Pattern di gestione delle eccezioni più usati
- 7.1 1. Gestione delle eccezioni per la lettura di file (try‑with‑resources)
- 7.2 2. Convalidare l’Input dell’Utente e Gestire le Eccezioni
- 7.3 3. Categorizzare le Eccezioni con Blocchi catch Multipli
- 7.4 4. Registrare un’Eccezione e Rilanciarla (Molto Comune nella Pratica)
- 7.5 5. Gestione delle Eccezioni per le Chiamate API e la Comunicazione con i Servizi
- 7.6 6. Definire Classi di Eccezione Personalizzate (Pattern Avanzato)
- 7.7 Migliori Pratiche di Gestione delle Eccezioni per Progetti Reali
- 8 7. Differenze tra versioni Java e gestione delle eccezioni specifica del framework
- 9 1. Evoluzione della gestione delle eccezioni nelle versioni Java
- 10 2. Eccezioni controllate vs. non controllate (riviste)
- 11 3. Gestione delle eccezioni in Spring (Spring Boot)
- 12 4. Come pensare al design delle eccezioni nei progetti reali
- 13 8. Sommario: Usare correttamente try rende il codice Java molto più stabile
- 14 ◆ Considerazioni finali
- 15 9. FAQ: Domande frequenti su try e gestione delle eccezioni in Java
- 15.1 Q1. Try e catch devono sempre essere scritti insieme?
- 15.2 Q2. Quale tipo di eccezione dovrei specificare nel catch?
- 15.3 Q3. Il finally è sempre necessario?
- 15.4 Q4. Perché i blocchi try dovrebbero essere mantenuti piccoli?
- 15.5 Q5. Perché “inghiottire le eccezioni” è così dannoso?
- 15.6 Q6. Non capisco la differenza tra throw e throws.
- 15.7 Q7. Il try-with-resources dovrebbe essere sempre usato?
- 15.8 Q8. Perché Spring Boot usa raramente try/catch?
- 15.9 Q9. Più eccezioni sono sempre meglio?
- 15.10 Q10. Qual è la migliore pratica per la gestione delle eccezioni in una frase?
1. Introduzione: Perché “try” è importante in Java
Quando si scrivono programmi in Java, inevitabilmente si dovrà affrontare la gestione delle eccezioni. Lettura di file, comunicazione di rete, calcoli numerici, input dell’utente—i programmi possono incontrare errori inaspettati in qualsiasi momento. Quando si verifica un’“eccezione”, se non ci sono salvaguardie in atto, il programma si arresta immediatamente e il processo termina a metà.
È qui che entra in gioco la sintassi di gestione delle eccezioni di Java incentrata su try.
try è un meccanismo per “avvolgere in modo sicuro” il codice che può generare un errore, ed è una parte estremamente importante del linguaggio che garantisce il comportamento stabile di Java.
Cosa fa l’istruzione try
- Impedisce al programma di fermarsi a causa di errori inaspettati
- Consente di controllare correttamente cosa succede in situazioni anomale (log, visualizzazione di messaggi, rilascio di risorse, ecc.)
- Separa chiaramente il flusso normale dal flusso di errore
- Garantisce “sicurezza” e “affidabilità”, elementi essenziali nel lavoro reale
In questo modo, try agisce come un “dispositivo di sicurezza” che stabilizza i programmi Java.
All’inizio può sembrare un po’ difficile da afferrare, ma una volta compreso, la qualità del tuo codice migliora notevolmente.
A chi è rivolto questo articolo
- Persone che hanno appena iniziato a imparare Java
- Persone che non sono sicure del modo corretto di scrivere try/catch
- Persone che vogliono rivedere try-with-resources e la propagazione delle eccezioni
- Persone che desiderano apprendere le migliori pratiche per la gestione delle eccezioni a livello professionale
In questo articolo spiegheremo tutto in ordine—dalle basi di try ai pattern avanzati, dagli errori comuni agli approcci pratici.
2. Le basi di try: sintassi e funzionamento
Per capire la gestione delle eccezioni, la prima cosa da apprendere è la struttura base try / catch. La gestione delle eccezioni in Java è progettata per separare chiaramente “il codice che può generare un’eccezione” dal “codice da eseguire se si verifica un’eccezione”.
Sintassi base di try / catch
La sintassi più elementare per la gestione delle eccezioni in Java è la seguente:
try {
// Code that may throw an exception
} catch (Exception e) {
// Code to run when an exception occurs
}
Se si verifica un’eccezione durante l’esecuzione del codice all’interno del blocco try, l’esecuzione viene interrotta immediatamente e il controllo passa al blocco catch. D’altra parte, se non si verifica alcuna eccezione, il blocco catch non viene eseguito e il programma procede al passo successivo.
Flusso di esecuzione base
- Eseguire il codice all’interno del blocco try in ordine
- Interrompere immediatamente al verificarsi di un’eccezione
- Saltare al blocco catch corrispondente
- Eseguire il codice all’interno di catch
- Al termine di catch, continuare con il codice al di fuori di try/catch
Questo flusso impedisce al programma intero di fermarsi anche quando si verifica un errore improvviso.
Esempio per principianti: divisione per zero
Come esempio facile da capire, diamo un’occhiata a “divisione per zero”.
try {
int result = 10 / 0; // Division by zero → exception occurs
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Error: You cannot divide by zero.");
}
Punti chiave
10 / 0genera unArithmeticException- Le righe rimanenti all’interno di try (l’istruzione di stampa) non vengono eseguite
- Invece, viene stampato il messaggio all’interno di catch
In questo modo, try viene usato per avvolgere “la parte che potrebbe andare storta”, e funge da punto di ingresso per la gestione delle eccezioni.
Come scegliere il tipo di eccezione in catch?
All’interno delle parentesi di catch, è necessario specificare il “tipo” di eccezione che si desidera gestire.
Esempi:
catch (IOException e)
catch (NumberFormatException e)
Java ha molte classi di eccezione, ognuna delle quali rappresenta un tipo specifico di errore.
Come principiante, va bene catturare in modo generico usando Exception, ma nello sviluppo reale è meglio specificare tipi di eccezione più concreti ogni volta che è possibile, perché rende l’analisi delle cause radice e il debug molto più facili.
Cosa Succede Se Non Si Verifica Nessuna Eccezione?
Se non si verifica alcuna eccezione:
- Il blocco try viene eseguito fino alla fine
- Il blocco catch viene saltato
- Il programma continua al passaggio di elaborazione successivo
È utile ricordare che le eccezioni si verificano “solo in situazioni anormali”.
3. Come Usare catch, finally, throw e throws
Nella gestione delle eccezioni in Java, ci sono più costrutti usati insieme a try.
Ognuno ha un ruolo diverso, e usarli correttamente ti aiuta a scrivere codice leggibile e sicuro.
Qui spiegheremo catch / finally / throw / throws in modo adatto ai principianti.
catch: Il Blocco Che Riceve e Gestisce le Eccezioni
catch è il blocco usato per gestire le eccezioni che si verificano all’interno di try.
try {
int num = Integer.parseInt("abc"); // NumberFormatException
} catch (NumberFormatException e) {
System.out.println("Cannot convert to a number.");
}
Punti chiave
- Gestisce solo le eccezioni che si verificano all’interno di
try - Specificando un tipo di eccezione, puoi reagire solo a errori specifici
- Puoi inserire più blocchi
catchper gestire le diverse eccezioni in modo differentetry { // Some processing } catch (IOException e) { // File-related error } catch (NumberFormatException e) { // Data format error }
finally: Codice Che Viene Sempre Eseguito, Anche Se Si Verifica Un’eccezione
Il blocco finally è dove scrivi il codice che deve essere eseguito indipendentemente dal verificarsi di un’eccezione.
try {
FileReader fr = new FileReader("data.txt");
} catch (IOException e) {
System.out.println("Could not open the file.");
} finally {
System.out.println("Finishing processing.");
}
Casi d’uso comuni
- Chiusura di file o connessioni di rete
- Disconnessione di connessioni al database
- Rilascio di risorse allocate temporaneamente
In breve, usa finally quando vuoi assicurarti che la pulizia avvenga sempre.
throw: Attivare Manualmente un’Eccezione
throw è una parola chiave usata per attivare esplicitamente un’eccezione.
public void checkAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Invalid age");
}
}
Quando usarlo
- Avvertire quando vengono passati argomenti non validi
- Casi che dovrebbero essere trattati come eccezioni in base alla logica di business
- Forzare un’eccezione quando rilevi uno “stato non valido”
Con throw, gli sviluppatori possono intenzionalmente deviare il flusso del programma verso un percorso di eccezione.
throws: Dichiarare Che un Metodo Può Propagare un’Eccezione al Chiamante
Scritta nella firma del metodo, significa:
“Questo metodo può lanciare una specifica eccezione, quindi il chiamante deve gestirla.”
public void readFile() throws IOException {
FileReader fr = new FileReader("test.txt");
}
Il ruolo di throws
- Non gestire l’eccezione all’interno del metodo
- Delegare la gestione dell’eccezione al chiamante
- Rendere chiara la responsabilità dichiarandola nella firma del metodo
Nei progetti reali, decisioni di design come
“Dove catturiamo le eccezioni e dove le propaghiamo verso l’alto?”
hanno un impatto significativo sulla qualità complessiva del codice.
Riepilogo delle Differenze Tra i Quattro
| Keyword | Role |
|---|---|
| try | Wrap code that might throw an exception |
| catch | Catch and handle an exception that occurred |
| finally | Always executes regardless of whether an exception occurred |
| throw | Manually throw an exception |
| throws | Declare that a method may throw an exception |
Una volta compreso questo, il quadro complessivo della gestione delle eccezioni diventa molto più chiaro.
4. Pattern Avanzati: try-with-resources e Propagazione delle Eccezioni
La gestione delle eccezioni in Java è molto utile anche con il semplice try / catch, ma esistono anche “pattern avanzati” che ti aiutano a gestire le eccezioni in modo più sicuro ed efficiente. Nello sviluppo reale, il modo in cui gestisci la pulizia delle risorse e la propagazione delle eccezioni può influire in modo significativo sulla qualità del codice.
Qui spiegheremo try-with-resources (introdotto in Java 7) e il meccanismo della propagazione delle eccezioni, dove le eccezioni viaggiano attraverso i confini dei metodi.
try-with-resources: Chiusura Automatica delle Risorse
Molte operazioni—file, socket, connessioni al database—richiedono la gestione delle “risorse”.
Ogni volta che apri una risorsa, devi chiuderla. Tradizionalmente, dovevi chiamare manualmente close() in un blocco finally.
Tuttavia, la chiusura manuale è facile da dimenticare e, se si verifica un’eccezione, le risorse potrebbero non venire chiuse correttamente.
È proprio per questo che è stato introdotto try-with-resources.
Sintassi Base di try-with-resources
try (FileReader fr = new FileReader("data.txt")) {
// File operations
} catch (IOException e) {
System.out.println("Failed to read the file.");
}
Qualsiasi risorsa dichiarata tra le parentesi di try avrà close() chiamato automaticamente, indipendentemente dal verificarsi o meno di un’eccezione.
Perché try-with-resources è Comodo
- Nessun rischio di dimenticare di chiudere le risorse
- Nessuna necessità di scrivere logica di chiusura lunga in
finally - Codice più breve e leggibile
- Gestito in modo sicuro anche se
close()stesso lancia un’eccezione
Nel lavoro reale, le operazioni su file e le connessioni al DB sono comuni, quindi usare try-with-resources ogni volta che è possibile è fortemente consigliato.
Gestione di Più Risorse Insieme
try (
FileReader fr = new FileReader("data.txt");
BufferedReader br = new BufferedReader(fr)
) {
String line = br.readLine();
System.out.println(line);
}
Puoi elencare più risorse e tutte verranno chiuse automaticamente, il che è estremamente comodo.
Propagazione delle Eccezioni: Come le Eccezioni Si Spostano Verso Metodi di Livello Superiore
Un altro concetto importante è la “propagazione delle eccezioni”.
Quando un’eccezione si verifica all’interno di un metodo e non la gestisci con try / catch in quel punto, l’eccezione propaga al chiamante così com’è.
Esempio di Propagazione di un’Eccezione (throws)
public void loadConfig() throws IOException {
FileReader fr = new FileReader("config.txt");
}
Il chiamante di questo metodo deve gestire l’eccezione:
try {
loadConfig();
} catch (IOException e) {
System.out.println("Cannot read the configuration file.");
}
Vantaggi della Propagazione
- Puoi evitare di sovraccaricare i metodi di livello inferiore con troppa gestione degli errori e delegare la responsabilità a livelli più alti
- La struttura dei metodi diventa più chiara e la leggibilità migliora
- Puoi centralizzare il logging e la gestione delle eccezioni in un unico punto
Svantaggi (Cose da Tenere d’Occhio)
- Devi capire dove le eccezioni vengono infine catturate
- Se il codice di livello superiore dimentica di gestirle, il programma si interromperà
- L’uso eccessivo di
throwsrende le dichiarazioni dei metodi più pesanti e più difficili da gestire
Nei progetti reali è importante decidere durante la progettazione:
“Dove dovremmo catturare le eccezioni e dove dovremmo propagarle?”
try-with-resources e Propagazione delle Eccezioni Possono Essere Combinati
public void readData() throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
System.out.println(br.readLine());
}
}
- Le risorse vengono chiuse automaticamente
- Le eccezioni propagano naturalmente al chiamante
- Il codice rimane breve e diventa più sicuro
Questo è uno stile altamente pratico per lo sviluppo reale.
5. Errori Comuni, Anti‑Pattern e Come Correggerli
La gestione delle eccezioni in Java è molto potente, ma usarla in modo errato può rendere il codice più difficile da leggere e creare terreno fertile per bug.
Specialmente dal livello principiante a quello intermedio, esistono molti “anti‑pattern” (modelli da evitare) che frequentemente diventano problemi reali in produzione.
Qui spiegheremo gli errori rappresentativi e come affrontarli.
1. Il Blocco try è Troppo Grande
try {
// A very long process, like 100 lines...
} catch (Exception e) {
// Handling when an exception occurs
}
Problemi
- Non è chiaro quale riga possa generare un’eccezione
- Individuare la causa diventa molto difficile quando si verificano bug
- La gestione delle eccezioni può essere applicata a codice che non ne ha bisogno
Soluzione
- Avvolgere solo la parte che può effettivamente generare un’eccezione
- Separare chiaramente la logica di business dalla gestione delle eccezioni
// Pre-processing try { loadConfig(); // Only this part can throw an exception } catch (IOException e) { // Error handling } // Post-processing
2. Lasciare il catch vuoto (Inghiottire l’eccezione)
try {
int n = Integer.parseInt(input);
} catch (NumberFormatException e) {
// Do nothing (silently ignore)
}
Questo è uno dei peggiori anti‑pattern.
Problemi
- Non hai alcuna idea che si sia verificato un errore
- I bug non possono essere scoperti e il debug diventa impossibile
- Nei progetti reali, questo può portare direttamente a incidenti gravi
Soluzione
- Scrivi sempre dei log o mostra un errore all’utente
- Come ultima risorsa, puoi rilanciare l’eccezione
catch (NumberFormatException e) { System.err.println("Invalid input: " + e.getMessage()); }
3. Catturare eccezioni con un tipo troppo generico
catch (Exception e) {
// Catch everything
}
Problemi
- È difficile identificare cosa sia realmente accaduto
- Potresti gestire accidentalmente eccezioni che non dovresti gestire
- Errori importanti possono rimanere nascosti
Soluzione
- Specifica un tipo di eccezione più concreto ogni volta che è possibile
- Se davvero devi raggruppare eccezioni, usa il “multi‑catch”
catch (IOException | NumberFormatException e) { // Handle multiple exceptions together }
4. Lanciare un’eccezione all’interno di finally
finally {
throw new RuntimeException("Exception thrown in finally");
}
Problemi
- L’“eccezione originale” del try/catch può andare persa
- Gli stack trace diventano confusi e il debug è difficile
- Nei progetti reali, questo può rendere quasi impossibile l’indagine sulla causa radice
Soluzione
- Scrivi solo codice di pulizia in finally
- Non aggiungere logica che lanci eccezioni
5. Dimenticare di chiamare close()
Questo accade spesso con l’approccio tradizionale try/finally.
FileReader fr = new FileReader("data.txt");
// Forgot to call close() → memory leaks, file locks remain
Soluzione: Usa try‑with‑resources
try (FileReader fr = new FileReader("data.txt")) {
// Safe auto-close
}
Quando è necessario gestire risorse, dovresti generalmente considerare try‑with‑resources come standard predefinito.

6. Pensare “Dovrei lanciare tutto con throws”
public void execute() throws Exception {
// Delegate everything to throws
}
Problemi
- Il chiamante si riempie di gestione delle eccezioni e il design si deteriora
- Diventa poco chiaro chi è responsabile della gestione degli errori
Soluzione
- Cattura solo le eccezioni che dovresti gestire nei metodi di livello inferiore
- Propaga solo le eccezioni critiche verso l’alto (l’equilibrio è importante)
Principi fondamentali per prevenire gli anti‑pattern
- Mantieni i blocchi try il più piccoli possibile
- Usa tipi di eccezione concreti nei catch
- Usa finally solo per la pulizia
- Non scrivere mai un blocco catch vuoto
- Standardizza la gestione delle risorse con try‑with‑resources
- Progetta le eccezioni tenendo conto della “responsabilità”
- Scrivi sempre dei log
Seguire questi principi da soli può migliorare drasticamente la qualità del codice.
6. Esempi di codice pratici: Pattern di gestione delle eccezioni più usati
In questa sezione, presentiamo i pattern di gestione delle eccezioni più comunemente usati nello sviluppo Java reale, con esempi di codice concreti. Invece di fermarci alle sole spiegazioni sintattiche, questi esempi sono pensati per essere applicati direttamente nei progetti.
1. Gestione delle eccezioni per la lettura di file (try‑with‑resources)
Uno dei casi più comuni è la gestione delle eccezioni per le operazioni sui file.
Poiché l’accesso ai file può fallire facilmente, la gestione delle eccezioni è essenziale.
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("An error occurred while reading the file: " + e.getMessage());
}
Punti chiave
- try-with-resources elimina la necessità di chiudere esplicitamente
- Catturare IOException è l’approccio standard
- Registrare la causa in caso di errore facilita l’indagine
2. Convalidare l’Input dell’Utente e Gestire le Eccezioni
L’input dell’utente è una fonte comune di bug.
I valori di input non validi sono spesso trattati come eccezioni.
public int parseAge(String input) {
try {
int age = Integer.parseInt(input);
if (age < 0) {
throw new IllegalArgumentException("Age must be zero or greater");
}
return age;
} catch (NumberFormatException e) {
throw new NumberFormatException("Please enter a numeric value");
}
}
Usi comuni nel mondo reale
- Convalida dell’input
- Controllo dei messaggi di errore
- Utilizzare
throwper convertire intenzionalmente errori logici in eccezioni
3. Categorizzare le Eccezioni con Blocchi catch Multipli
Quando più tipi di eccezioni possono verificarsi in un unico processo,
puoi preparare più blocchi catch per distinguere tra i tipi di errore.
try {
processTask();
} catch (IOException e) {
System.out.println("I/O error: " + e.getMessage());
} catch (NullPointerException e) {
System.out.println("An unexpected null value was detected");
} catch (Exception e) {
System.out.println("An unexpected error occurred");
}
Benefici
- Più facile identificare la causa degli errori
- Consente di indirizzare la logica di gestione appropriata
4. Registrare un’Eccezione e Rilanciarla (Molto Comune nella Pratica)
Nei sistemi reali, è comune registrare un’eccezione e poi rilanciarla al chiamante.
try {
processData();
} catch (IOException e) {
System.err.println("Log: An I/O error occurred during data processing");
throw e; // Propagate the exception to the caller
}
Perché è pratico
- I log facilitano l’indagine
- La responsabilità della gestione delle eccezioni può essere delegata a livelli superiori
5. Gestione delle Eccezioni per le Chiamate API e la Comunicazione con i Servizi
Il codice che comunica con API o servizi esterni è soggetto a fallimenti.
try {
String response = httpClient.get("https://example.com/api");
System.out.println("Response: " + response);
} catch (IOException e) {
System.out.println("A communication error occurred. Please try again.");
}
Cose da Tenere a Mente
- La comunicazione di rete ha un’alta probabilità di eccezioni
- Potrebbe essere necessaria una logica di retry
- Gli errori basati sullo stato HTTP dovrebbero spesso essere gestiti separatamente
6. Definire Classi di Eccezione Personalizzate (Pattern Avanzato)
Man mano che i progetti crescono, potresti definire eccezioni specifiche dell’applicazione.
public class InvalidUserException extends Exception {
public InvalidUserException(String message) {
super(message);
}
}
public void validateUser(User user) throws InvalidUserException {
if (user == null) {
throw new InvalidUserException("Invalid user data");
}
}
Benefici
- Personalizzare i tipi di errore per adattarli al dominio del progetto
- Progettare strutture di eccezione allineate alla logica di business
Migliori Pratiche di Gestione delle Eccezioni per Progetti Reali
- Mantieni i blocchi try il più piccoli possibile
- Usa try-with-resources quando possibile
- Specifica tipi concreti di eccezione nel catch
- Non scrivere mai blocchi catch vuoti
- Registra le eccezioni e rilanciale quando opportuno
- Definisci chiaramente la responsabilità della gestione delle eccezioni
Applicare questi principi porta a codice stabile e manutenibile nei progetti reali.
7. Differenze tra versioni Java e gestione delle eccezioni specifica del framework
Il meccanismo di gestione delle eccezioni di Java esiste da molto tempo, ma con ogni versione sono state aggiunte nuove funzionalità, ampliando le modalità di utilizzo. Inoltre, i framework comunemente usati nei progetti reali — come Spring — spesso hanno proprie filosofie di gestione delle eccezioni, che differiscono dal Java puro.
Qui spiegheremo le differenze versione per versione in Java e come la gestione delle eccezioni viene affrontata nei principali framework.
1. Evoluzione della gestione delle eccezioni nelle versioni Java
Java 7: L’introduzione di try-with-resources (un cambiamento rivoluzionario)
Prima di Java 7, la pulizia delle risorse doveva sempre essere scritta in un blocco finally.
FileReader fr = null;
try {
fr = new FileReader("data.txt");
} finally {
if (fr != null) fr.close();
}
Problemi
- Codice verboso
close()può anche lanciare eccezioni, richiedendo try/catch annidati- Le perdite di risorse sono facili da introdurre
Risolto da try-with-resources in Java 7
try (FileReader fr = new FileReader("data.txt")) {
// Read data
}
- close() viene chiamato automaticamente
- Nessun bisogno di finally
- Semplice e sicuro
→ Una delle aggiornamenti più importanti nello sviluppo Java pratico.
Java 8: Gestione degli errori combinata con le espressioni lambda
Java 8 ha introdotto le espressioni lambda, rendendo più comune la gestione delle eccezioni all’interno dell’elaborazione di stream.
List<String> list = Files.lines(Paths.get("test.txt"))
.collect(Collectors.toList());
Quando si verifica un IOException all’interno di uno stream, le eccezioni verificate diventano difficili da gestire. Di conseguenza, un pattern comune è avvolgere le eccezioni verificate in RuntimeException.
Java 9 e versioni successive: miglioramenti a try-with-resources
In Java 9, le variabili già dichiarate possono essere passate a try-with-resources.
BufferedReader br = new BufferedReader(new FileReader("data.txt"));
try (br) {
System.out.println(br.readLine());
}
Vantaggi
- Creare le risorse in anticipo e includerle successivamente in try-with-resources
- Flessibilità migliorata
2. Eccezioni controllate vs. non controllate (riviste)
Le eccezioni Java sono divise in due categorie.
Eccezioni controllate
- IOException
- SQLException
- ClassNotFoundException
→ Deve essere dichiarata con throws o gestita esplicitamente.
Eccezioni non controllate
- NullPointerException
- IllegalArgumentException
- ArithmeticException
→ Nessuna dichiarazione throws richiesta.
→ Si verificano a runtime.
In pratica, una regola empirica comune è:
Errori di business recuperabili → eccezioni controllate
Difetti di programmazione → eccezioni non controllate
3. Gestione delle eccezioni in Spring (Spring Boot)
In Spring / Spring Boot, uno dei framework Java più usati, la gestione delle eccezioni è progettata in modo leggermente diverso.
Caratteristiche dell’approccio di Spring
- Le eccezioni sono spesso unificate come RuntimeException (non controllate)
- Le eccezioni sono separate per i layer DAO, Service e Controller
- Gestione centralizzata usando
@ExceptionHandlere@ControllerAdvice
Esempio: gestione delle eccezioni nel layer Controller
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return ResponseEntity.status(500).body("A server error occurred");
}
}
Vantaggi
- Centralizza la gestione delle eccezioni in un unico punto
- Elimina i blocchi try/catch non necessari nei controller
- Adatto a servizi su larga scala
4. Come pensare al design delle eccezioni nei progetti reali
- Gestire le eccezioni recuperabili a livello di business negli strati inferiori
- Propagare le eccezioni non gestibili verso l’alto e gestirle nello strato Controller
- Registrare informazioni dettagliate per operazioni ad alto rischio come API esterne e accessi al DB
- Standardizzare i tipi di eccezione all’interno del progetto
- Identificare quali eccezioni sono recuperabili (ad es. retry)
Piuttosto che concentrarsi solo sulla sintassi Java,
progettare il comportamento complessivo dell’applicazione è ciò che conta davvero.
8. Sommario: Usare correttamente try rende il codice Java molto più stabile
In questo articolo abbiamo trattato la gestione delle eccezioni in Java incentrata sulla istruzione try, dai fondamenti all’uso pratico, agli anti‑pattern e persino alle differenze tra versioni. La gestione delle eccezioni spesso sembra difficile per i principianti, ma una volta compresa correttamente diventa uno strumento potente che migliora notevolmente la qualità del codice.
Rivediamo i punti chiave.
◆ Comprendere il ruolo dell’istruzione try
- Un meccanismo per avvolgere in sicurezza il codice che può generare eccezioni
- Previene la terminazione anomala del programma e migliora la stabilità
- Separa chiaramente il flusso normale da quello di errore
Il primo passo nella gestione delle eccezioni è capire come funziona try/catch.
◆ Utilizzare correttamente catch, finally, throw e throws
- catch : Cattura e gestisce le eccezioni
- finally : Scrive il codice di pulizia che deve sempre essere eseguito
- throw : Lancia intenzionalmente un’eccezione
- throws : Delega la gestione dell’eccezione al chiamante
Comprendere le differenze tra questi ruoli rende molto più semplice il design della gestione delle eccezioni.
◆ try-with-resources è essenziale nella pratica
Introdotto in Java 7, questa sintassi offre un vantaggio importante:
“Chiudere le risorse in modo sicuro e automatico.”
Per il codice che gestisce file, reti o database,
usare try-with-resources come standard è una pratica comune nello sviluppo Java moderno.
◆ Evitare errori comuni migliora drasticamente la qualità
- Blocchi try troppo grandi
- Blocchi catch vuoti
- Uso eccessivo di Exception per catturare tutto
- Lanciare eccezioni dentro finally
- Dimenticare di chiudere le risorse
Questi sono ostacoli frequenti per principianti e sviluppatori intermedi.
Evitarli da soli può rendere il tuo codice notevolmente migliore.
◆ Decidere dove gestire le eccezioni è cruciale nei progetti reali
- Eccezioni da gestire negli strati inferiori
- Eccezioni da propagare agli strati superiori
- Gestione centralizzata in framework come Spring
La gestione delle eccezioni influisce non solo sulla qualità del codice ma anche su
l’architettura complessiva dell’applicazione.
◆ Considerazioni finali
L’istruzione try è una parte fondamentale della gestione delle eccezioni in Java, ma influisce anche su
stabilità, leggibilità e manutenibilità del codice.
Anche se all’inizio può sembrare difficile, concentrarsi su:
- Come funzionano le eccezioni
- Come usare try-with-resources
- Tenere i blocchi try ridotti al minimo
- Progettare blocchi catch appropriati
ti permetterà di approfondire gradualmente la comprensione.
Nel sviluppo reale,
decidere “dove gestire le eccezioni” e mantenere un design coerente delle eccezioni
aiuta a costruire applicazioni robuste.
Speriamo che questo articolo ti aiuti a comprendere l’istruzione try di Java e la gestione delle eccezioni,
e ti supporti nella scrittura di codice stabile e affidabile.
9. FAQ: Domande frequenti su try e gestione delle eccezioni in Java
Q1. Try e catch devono sempre essere scritti insieme?
A. Nella maggior parte dei casi, sì. Tuttavia, esistono eccezioni valide come try-with-resources combinato con finally.
Nella sintassi standard,
try { ... } catch (...) { ... }
viene tipicamente usato come coppia.
Tuttavia, le seguenti combinazioni sono anch’esse valide:
try + finallytry-with-resources + catchtry-with-resources + finally
Q2. Quale tipo di eccezione dovrei specificare nel catch?
A. Come regola generale, specifica il tipo di eccezione concreto che può effettivamente verificarsi in quel processo.
Esempi:
- Operazioni su file →
IOException - Conversione di numeri →
NumberFormatException - Accesso a un array →
ArrayIndexOutOfBoundsException
Catturare tutto con Exception può sembrare comodo,
ma nella pratica rende difficile capire cosa è realmente accaduto e dovrebbe essere evitato.
Q3. Il finally è sempre necessario?
A. No. Usalo solo quando hai del codice di pulizia che deve sempre essere eseguito.
Dal Java 7,
- File
- Socket
- Connessioni al database
sono tipicamente gestiti con try-with-resources, e in molti casi non è più necessario il finally.
Q4. Perché i blocchi try dovrebbero essere mantenuti piccoli?
A. Perché rende molto più facile identificare dove si è verificata un’eccezione.
Se i blocchi try sono troppo grandi:
- Non riesci a capire dove si è verificato l’errore
- Il codice normale è incluso inutilmente nella gestione delle eccezioni
- Il debug diventa difficile
Q5. Perché “inghiottire le eccezioni” è così dannoso?
A. Perché gli errori sono nascosti e la causa radice potrebbe non essere mai scoperta.
Esempio:
catch (Exception e) {
// Do nothing ← NG
}
Questo è uno dei pattern più odiati nello sviluppo reale.
Al minimo, registra l’errore o mostra un messaggio appropriato.
Q6. Non capisco la differenza tra throw e throws.
A. throw significa “lanciare effettivamente un’eccezione”, mentre throws significa “dichiarare che un’eccezione può essere lanciata”.
throw: Lancia attivamente un’eccezionethrows: Dichiara la possibilità di un’eccezione
Esempi:
throw new IllegalArgumentException(); // Throw here
public void load() throws IOException {} // Declare possibility
Q7. Il try-with-resources dovrebbe essere sempre usato?
A. È quasi obbligatorio quando è necessaria la gestione delle risorse.
- Chiusura automatica (
close()) - Nessuna necessità di
finally - Codice conciso
- Sicuro anche quando si verificano eccezioni
Nello sviluppo Java moderno, il try-with-resources è considerato lo standard.
Q8. Perché Spring Boot usa raramente try/catch?
A. Perché Spring fornisce meccanismi centralizzati di gestione delle eccezioni come @ExceptionHandler e @ControllerAdvice.
Questo consente:
- Catturare le eccezioni a livello di Controller
- Risposte di errore unificate
- Logica di business rimane focalizzata e pulita
Q9. Più eccezioni sono sempre meglio?
A. No. Lanciare troppe eccezioni rende il codice più difficile da leggere.
Idee chiave:
- Gestire le eccezioni recuperabili a livello di business
- Trattare i difetti di programmazione come
RuntimeException - Definire chiaramente la responsabilità della gestione delle eccezioni
Q10. Qual è la migliore pratica per la gestione delle eccezioni in una frase?
A. “Mantieni i blocchi try piccoli, cattura eccezioni specifiche, usa finally solo quando necessario e chiudi le risorse automaticamente.”
Seguire questo principio da solo migliorerà notevolmente la qualità della tua gestione delle eccezioni.
