2010-08-16 9 views
516

In Java, voglio fare qualcosa di simile:Posso catturare più eccezioni Java nella stessa clausola catch?

try { 
    ...  
} catch (IllegalArgumentException, SecurityException, 
     IllegalAccessException, NoSuchFieldException e) { 
    someCode(); 
} 

... invece di:

try { 
    ...  
} catch (IllegalArgumentException e) { 
    someCode(); 
} catch (SecurityException e) { 
    someCode(); 
} catch (IllegalAccessException e) { 
    someCode(); 
} catch (NoSuchFieldException e) { 
    someCode(); 
} 

Esiste un modo per fare questo?

risposta

849

Questo è possibile since Java 7. La sintassi per blocco try-catch è:

try { 
    ... 
} catch (IOException | SQLException ex) { 
    ... 
} 

Prima di Java 7 questo non era possibile. Ricorda però che se tutte le eccezioni appartengono alla stessa gerarchia di classi, puoi semplicemente catturare quel tipo di eccezione di base. L'unico altro modo è catturare ogni eccezione nel proprio blocco di cattura.

Modifica: si noti che in Java 7, non è possibile rilevare sia ExceptionA che ExceptionB nello stesso blocco se ExceptionB è ereditato, direttamente o indirettamente, da ExceptionA. Il compilatore si lamenterà: The exception ExceptionB is already caught by the alternative ExceptionA.

+67

T.T - perché ridefinire l'operatore 'bitwise o' (' | ')? Perché non usare una virgola, o l'operatore che ha un significato più simile, il 'logico o' (' || ')? – ArtOfWarfare

+8

@ArtOfWarfare Forse hanno pensato che non avrebbe più avuto importanza dopo che avevano già elaborato la sintassi per [più limiti] (http://docs.oracle.com/javase/tutorial/java/generics/bounded.html) per farmaci generici. – JimmyB

+0

@JimmyB Potresti spiegare di più sui molteplici limiti per i generici? Grazie. – ZhaoGang

15

No, uno per cliente.

È possibile catturare una superclasse, come java.lang.Exception, a condizione che si esegua la stessa azione in tutti i casi.

try { 
    // some code 
} catch(Exception e) { //All exceptions are caught here as all are inheriting java.lang.Exception 
    e.printStackTrace(); 
} 

Ma questa potrebbe non essere la migliore pratica. Dovresti solo rilevare un'eccezione quando hai una strategia per gestirla effettivamente - e il logging e il rethrowing non lo "maneggiano". Se non si dispone di un'azione correttiva, è meglio aggiungerla alla firma del metodo e lasciarla diventare una bolla in grado di gestire la situazione.

+15

Posso presentare una petizione a riformulare la parte circa la cattura java.lang.Exception? Mi rendo conto che è un esempio, ma mi sento come se alcune persone potessero leggere questa risposta e dire "oh, okay, prenderò solo Exception", quando questo probabilmente non è ciò che vogliono (o dovrebbero) fare. –

+0

Vedi se è meglio. – duffymo

+1

Lo sapevo, ma non voglio farlo ... Oh, beh, credo di essere bloccato con 4 prese, fino alla prossima versione di Java ... – froadie

0

Cattura l'eccezione che si verifica essere una classe genitore nella gerarchia di eccezioni. This is of course, bad practice. Nel tuo caso, l'eccezione genitore comune sembra essere la classe Exception e rilevare qualsiasi eccezione che sia un'istanza di Exception, è in effetti una cattiva pratica - eccezioni come NullPointerException sono di solito errori di programmazione e dovrebbero essere risolti controllando i valori null.

11

Se esiste una gerarchia di eccezioni, è possibile utilizzare la classe di base per catturare tutte le sottoclassi di eccezioni. Nel caso degenere si può prendere tutte eccezioni Java con:

try { 
    ... 
} catch (Exception e) { 
    someCode(); 
} 

In un caso più comune, se RepositoryException è la classe di base e PathNotFoundException è una classe derivata poi:

try { 
    ... 
} catch (RepositoryException re) { 
    someCode(); 
} catch (Exception e) { 
    someCode(); 
} 

È possibile che questo il codice catturerà RepositoryException e PathNotFoundException per un tipo di gestione delle eccezioni e tutte le altre eccezioni sono raggruppate insieme. Dal Java 7, come da @ di OscarRyz risposta di cui sopra:

try { 
    ... 
} catch(IOException | SQLException ex) { 
    ... 
} 
+5

BTW catturare clausole sono gestite in modo così se si mette una classe di eccezione genitore prima di una classe figlia, allora non è mai chiamato ad es: try { ... } catch (Exception e) { someCode(); } catch (RepositoryException re) { // non raggiunto mai } –

+2

In realtà proprio perché non può mai essere raggiunto, tale codice non viene nemmeno compilato. – polygenelubricants

19

All'interno Java 7 è possibile definire più clausole catch come:

catch (IllegalArgumentException | SecurityException e) 
{ 
    ... 
} 
96

Non esattamente prima di Java 7, ma, vorrei fare qualcosa di simile :

Java 6 e prima

try { 
    //..... 
} catch (Exception exc) { 
    if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || 
    exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException) { 

    someCode(); 

    } else if (exc instanceof RuntimeException) { 
    throw (RuntimeException) exc;  

    } else { 
    throw new RuntimeException(exc); 
    } 

} 



Java 7

try { 
    //..... 
} catch (IllegalArgumentException | SecurityException | 
     IllegalAccessException |NoSuchFieldException exc) { 
    someCode(); 
} 
+10

Si noti che l'esempio di Java 6 interrompe la capacità del compilatore di dire cosa verrà generato da dove. – MichaelBlume

+1

@MichaelBlume True, che non è [così] cattivo. Puoi sempre ottenere l'eccezione originale con 'exc.getCause()'. Come nota a margine, Robert C. Martin (tra gli altri) consiglia di utilizzare eccezioni non controllate (il compilatore non ha idea di quale tipo di eccezione verrà lanciata da lì); fare riferimento a _Capitolo 7: Gestione degli errori_ sul suo libro _Clean code_. – user454322

+2

Nel tuo esempio di Java 6 non dovresti rilanciare l'eccezione originale invece di creare una nuova istanza di eccezione, ad esempio "lanciare exc" invece di "lanciare una nuova RuntimeException (exc)"? –

6

A più pulito (ma meno prolissa, e forse non a scelta) alternativa alla risposta di user454322 su Java 6 (vale a dire, Android) sarebbe quello di catturare tutti Exception s e ri- buttare RuntimeException s. Questo non funzionerebbe se hai intenzione di catturare altri tipi di eccezioni più in alto nello stack (a meno che tu non li rilasci anche tu), ma riuscirà a catturare tutte le eccezioni selezionate.

Per esempio:

try { 
    // CODE THAT THROWS EXCEPTION 
} catch (Exception e) { 
    if (e instanceof RuntimeException) { 
     // this exception was not expected, so re-throw it 
     throw e; 
    } else { 
     // YOUR CODE FOR ALL CHECKED EXCEPTIONS 
    } 
} 

Detto questo, per la prolissità, potrebbe essere meglio per impostare un valore booleano o di qualche altra variabile e in base a tale eseguire del codice dopo il blocco try-catch.

+0

Questo approccio impedisce al compilatore di determinare se un "blocco catch" sarà raggiungibile o meno. –

3

In pre-7 che ne dici:

Boolean caught = true; 
    Exception e; 
    try { 
    ... 
    caught = false; 
    } catch (TransformerException te) { 
    e = te; 
    } catch (SocketException se) { 
    e = se; 
    } catch (IOException ie) { 
    e = ie; 
    } 
    if (caught) { 
    someCode(); // You can reference Exception e here. 
    } 
+2

essere una buona soluzione. Che ne dici di inserire il controllo finale di 'caught' in un blocco' finally'? –

+0

Ciò richiede più righe rispetto alla domanda originale. –