Blocchi try/catch annidati in Java
- I blocchi
try
possono essere annidati per gestire eccezioni in contesti complessi. - Un blocco
try
interno può intercettare eccezioni che non sono state gestite da un bloccotry
esterno. - Le eccezioni vengono propagate dal blocco
try
interno al bloccotry
esterno se non vengono gestite. - Le istruzioni
try
annidate possono essere utilizzate per gestire eccezioni in metodi chiamati, consentendo una gestione più flessibile delle eccezioni.
Istruzioni try
annidate
L'istruzione try
può essere annidata.
Vale a dire, un'istruzione try
può essere all'interno del blocco di un'altra try
. Ogni volta che viene eseguita un'istruzione try
, il contesto di quell'eccezione viene inserito nello stack.
Se un'istruzione try
interna non ha un gestore catch
per una particolare eccezione, lo stack viene smontato e i gestori catch
dell'istruzione try
successiva vengono ispezionati alla ricerca di una corrispondenza.
Questo continua finché uno dei blocchi catch
ha successo, oppure finché tutti i blocchi try
annidati sono stati esauriti. Se nessun blocco catch
ha successo, allora il sistema di runtime di Java gestirà l'eccezione. Ecco un esempio che utilizza istruzioni try
annidate:
// Un esempio di istruzioni try annidate.
class ProvaAnnidata {
public static void main(String[] args) {
try {
int a = args.length;
/* Se non sono presenti argomenti da linea di comando,
l'istruzione seguente genererà
un'eccezione di divisione per zero. */
int b = 42 / a;
System.out.println("a = " + a);
try { // blocco try annidato
/* Se viene usato un argomento da linea di comando,
verrà generata una divisione per zero dal codice seguente. */
if(a==1) a = a/(a-a); // divisione per zero
/* Se vengono usati due argomenti da linea di comando,
viene generata un'eccezione di indice fuori dai limiti. */
if(a==2) {
int[] c = { 1 };
c[42] = 99; // genera un'eccezione di indice fuori dai limiti
}
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Indice fuori dai limiti: " + e);
}
} catch(ArithmeticException e) {
System.out.println("Divisione per 0: " + e);
}
}
}
Come possiamo vedere, questo programma annida un blocco try
all'interno di un altro.
Il programma funziona come segue. Quando il programma viene eseguito senza argomenti da linea di comando, si verifica una divisione per zero che viene intercettata dal blocco try
esterno.
L'esecuzione del programma con un argomento da linea di comando genera una divisione per zero all'interno del blocco try
annidato. Poiché il blocco interno non intercetta questa eccezione, essa viene passata al blocco try
esterno, dove viene gestita. Se invece il programma viene eseguito con due argomenti da linea di comando, viene generata un'eccezione di limite dell'array all'interno del blocco try
interno. Ecco alcuni esempi di esecuzione che illustrano ciascun caso:
$ java ProvaAnnidata
Divisione per 0: java.lang.ArithmeticException: / by zero
$ java ProvaAnnidata Uno
a = 1
Divisione per 0: java.lang.ArithmeticException: / by zero
$ java ProvaAnnidata Uno Due
a = 2
Indice fuori dai limiti:
java.lang.ArrayIndexOutOfBoundsException:
Indice 42 fuori dai limiti per la lunghezza 1
L'annidamento delle istruzioni try
può verificarsi in modi meno ovvi quando sono coinvolte chiamate a metodi. Ad esempio, è possibile racchiudere una chiamata a un metodo all'interno di un blocco try
.
All'interno del metodo si trova un'altra istruzione try
. In questo caso, la try
all'interno del metodo è ancora annidata all'interno del blocco try
esterno, che chiama il metodo.
Ecco il programma precedente riscritto in modo che il blocco try
annidato venga spostato all'interno del metodo provaAnnidata()
:
/* Le istruzioni try possono essere annidate implicitamente tramite
chiamate a metodi. */
class MetodoProvaAnnidata {
static void provaAnnidata(int a) {
try { // blocco try annidato
/* Se viene usato un argomento da linea di comando,
verrà generata una divisione per zero dal codice seguente. */
if(a==1) a = a/(a-a); // divisione per zero
/* Se vengono usati due argomenti da linea di comando,
viene generata un'eccezione di indice fuori dai limiti. */
if(a==2) {
int[] c = { 1 };
c[42] = 99; // genera un'eccezione di indice fuori dai limiti
}
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Indice fuori dai limiti: " + e);
}
}
public static void main(String[] args) {
try {
int a = args.length;
/* Se non sono presenti argomenti da linea di comando,
l'istruzione seguente genererà
una divisione per zero. */
int b = 42 / a;
System.out.println("a = " + a);
provaAnnidata(a);
} catch(ArithmeticException e) {
System.out.println("Divisione per 0: " + e);
}
}
}
L'output di questo programma è identico a quello dell'esempio precedente.