Java Language Cattura un'eccezione con try-catch

Esempio

Un'eccezione può essere catturata e gestita usando la try...catch . (In effetti le dichiarazioni di try prendono altre forme, come descritto in altri esempi su try...catch...finally e try-with-resources .)

Prova a prendere con un blocco di cattura

La forma più semplice ha questo aspetto:

try {
    doSomething();
} catch (SomeException e) {
    handle(e);
}
// next statement

Il comportamento di un semplice try...catch è il seguente:

  • Le istruzioni nel blocco try vengono eseguite.
  • Se nessuna eccezione è generata dalle dichiarazioni nel blocco try , il controllo passa alla successiva dichiarazione dopo il try...catch .
  • Se viene lanciata un'eccezione all'interno del blocco try .
    • L'oggetto eccezione viene verificato per verificare se si tratta di un'istanza di SomeException o di un sottotipo.
    • Se lo è, il blocco catch attira l'eccezione:
      • La variabile e è associata all'oggetto eccezione.
      • Il codice all'interno del blocco catch viene eseguito.
      • Se quel codice genera un'eccezione, l'eccezione appena generata viene propagata al posto di quella originale.
      • Altrimenti, il controllo passa alla dichiarazione successiva dopo il try...catch .
    • Se non lo è, l'eccezione originale continua a propagarsi.

Prova a catturare con più catture

Un try...catch può anche avere più blocchi catch . Per esempio:

try {
    doSomething();
} catch (SomeException e) {
    handleOneWay(e)
} catch (SomeOtherException e) {
    handleAnotherWay(e);
}
// next statement

Se ci sono più blocchi catch , vengono provati uno alla volta iniziando dal primo, finché non viene trovata una corrispondenza per l'eccezione. Il gestore corrispondente viene eseguito (come sopra) e quindi il controllo viene passato all'istruzione successiva dopo l'istruzione try...catch . I blocchi catch dopo quello che corrisponde vengono sempre saltati, anche se il codice del gestore genera un'eccezione .

La strategia di abbinamento "top down" ha conseguenze per i casi in cui le eccezioni nei blocchi catch non sono disgiunte. Per esempio:

try {
    throw new RuntimeException("test");
} catch (Exception e) {
    System.out.println("Exception");
} catch (RuntimeException e) {
    System.out.println("RuntimeException");
}

Questo snippet di codice genererà "Eccezione" anziché "RuntimeException". Poiché RuntimeException è un sottotipo di Exception , il primo (più generale) catch verrà confrontato. La seconda catch (più specifica) non verrà mai eseguita.

La lezione da imparare da questo è che i blocchi di catch più specifici (in termini di tipi di eccezione) dovrebbero apparire per primi, e quelli più generali dovrebbero essere gli ultimi. (Alcuni compilatori Java ti avviseranno se una catch non può mai essere eseguita, ma questo non è un errore di compilazione.)

Blocchi di cattura multi-eccezione

Java SE 7

A partire da Java SE 7, un singolo blocco catch può gestire un elenco di eccezioni non correlate. Il tipo di eccezione è elencato, separato da un simbolo di barra verticale ( | ). Per esempio:

try {
    doSomething();
} catch (SomeException | SomeOtherException e) {
    handleSomeException(e);
} 

Il comportamento di un'eccezione a più eccezioni è un'estensione semplice per il caso a eccezione singola. Il catch corrisponde se l'eccezione generata soddisfa (almeno) una delle eccezioni elencate.

C'è qualche sottigliezza aggiuntiva nelle specifiche. Il tipo di e è un'unione sintetica dei tipi di eccezione nell'elenco. Quando viene utilizzato il valore di e , il suo tipo statico è il supertipo meno comune dell'unione di tipo. Tuttavia, se e viene ripubblicato all'interno del blocco catch , i tipi di eccezioni lanciati sono i tipi nell'unione. Per esempio:

public void method() throws IOException, SQLException
    try {
        doSomething();
    } catch (IOException | SQLException e) {
        report(e);
        throw e;
    }

In quanto sopra, IOException e SQLException sono eccezioni controllate il cui supertipo minimo comune è Exception . Ciò significa che il metodo del report deve corrispondere al report(Exception) . Tuttavia, il compilatore sa che il throw può generare solo IOException o SQLException . Pertanto, il method può essere dichiarato come throws IOException, SQLException piuttosto che throws Exception . (Che è una buona cosa: vedi Pitfall - Throwable Throwable, Exception, Error o RuntimeException .)