Posso rilevare più eccezioni Java nella stessa clausola catch?


699

In Java, voglio fare qualcosa del genere:

try {
    ...     
} catch (/* code to catch IllegalArgumentException, SecurityException, 
            IllegalAccessException, and NoSuchFieldException at the same time */) {
   someCode();
}

...invece di:

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

C'è un modo per fare questo?

Risposte:


1131

Questo è stato possibile da Java 7 . La sintassi per un blocco multi-catch è:

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

Ricorda, tuttavia, che se tutte le eccezioni appartengono alla stessa gerarchia di classi, puoi semplicemente prendere quel tipo di eccezione di base.

Si noti inoltre che non è possibile rilevare sia ExceptionA che ExceptionB nello stesso blocco se ExceptionB è ereditato, direttamente o indirettamente, da ExceptionA. Il compilatore si lamenterà:

Alternatives in a multi-catch statement cannot be related by subclassing
  Alternative ExceptionB is a subclass of alternative ExceptionA

81
TT: perché ridefinire l' operatore bitwise or( |)? Perché non usare una virgola o l'operatore che ha un significato più simile, il logical or( ||)?
ArtOfWarfare il

11
@ArtOfWarfare Forse hanno pensato che non avrebbe più avuto importanza dopo che avevano già escogitato la sintassi per più limiti per i generici.
JimmyB,

12
Il segno XOR (I) non è uguale a OR (||), A | B significa A o B ma non entrambi A || B significa A o B o entrambi, così come per le eccezioni è un'eccezione A o un'eccezione B ma non entrambe allo stesso tempo. questo è il motivo per cui hanno usato XOR sing invece di OR e puoi vederlo chiaramente quando viene
generata

41
@ user1512999 in Java, XOR bit a bit è ^ (punto di inserimento) e OR bit a bit è | (pipe) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
Lewis Baumstark

6
Vale la pena ricordare che il tipo di un'eccezione catturata nel blocco multi-catch viene valutata dal genitore comune più derivato
yanpas

104

Non esattamente prima di Java 7, ma farei qualcosa del genere:

Java 6 e precedenti

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();
}

11
Nota che il tuo esempio Java 6 interrompe la capacità del compilatore di dire cosa verrà lanciato da dove.
MichaelBlume,

2
@MichaelBlume True, che non è [così] male. Puoi sempre ottenere l'eccezione originale con exc.getCause(). Come nota a margine, Robert C. Martin (tra gli altri) raccomanda di usare eccezioni non controllate (il compilatore non ha idea di che tipo di eccezione verrà generata da lì); fare riferimento al Capitolo 7: Gestione degli errori nel suo libro Clean code .
user454322

4
Nel tuo esempio Java 6 non dovresti ricrescere l'eccezione originale invece di creare una nuova istanza di eccezione, ovvero throw excinvece di throw new RuntimeException(exc)?
David De

5
Questa è una brutta pratica, dal punto di vista della leggibilità.
Rajesh J Advani,

3
L'istanza di funzionamento è un po 'costosa, è meglio evitare il più possibile.
Paramesh Korrakuti,

23

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

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

16

Se esiste una gerarchia di eccezioni, è possibile utilizzare la classe base per rilevare tutte le sottoclassi di eccezioni. Nel caso degenerato è possibile rilevare tutte le eccezioni Java con:

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

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

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

Il codice sopra catturerà RepositoryException e PathNotFoundException per un tipo di gestione delle eccezioni e tutte le altre eccezioni vengono raggruppate insieme. Da Java 7, secondo la risposta @ OscarRyz sopra:

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

7
Le clausole di cattura BTW sono gestite in ordine, quindi se metti una classe di eccezione padre prima di una classe di figlio, non viene mai chiamata ad esempio: try {...} catch (Exception e) {someCode (); } catch (RepositoryException re) {// mai raggiunto}
Michael Shopsin

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

15

No, uno per cliente.

È possibile catturare una superclasse, come java.lang.Exception, purché 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 quella potrebbe non essere la migliore pratica. Dovresti cogliere un'eccezione solo quando hai una strategia per gestirla effettivamente - e il logging e il ri-lancio non significa "gestirla". Se non si dispone di un'azione correttiva, è meglio aggiungerlo alla firma del metodo e lasciarlo in bolla a qualcuno in grado di gestire la situazione.


20
Posso presentare una petizione per riformulare la parte relativa alla cattura di java.lang.Exception? Mi rendo conto che è un esempio, ma sento che alcune persone potrebbero leggere questa risposta e dire "oh, okay, allora prenderò l'eccezione", quando probabilmente non è quello che vogliono (o dovrebbero) fare.
Rob Hruska,

2
Lo sapevo, ma non voglio farlo ... Oh, beh, suppongo di essere bloccato con 4 catture allora, fino alla prossima versione di Java ...
froadie,

@duffymo: cosa c'è che non va nel logging e nel ri-lancio? Solo che ingombra il codice, equivale a non catturarlo, non è vero? Visto dal punto di vista della strategia generale di gestione degli errori. Ciò che è male è il logging e non il rilancio.
Frank Osterfeld,

5
Non prendo in considerazione la registrazione e il rilancio della gestione di nulla. Preferirei lasciarlo fare a qualcuno che sa fare qualcosa di significativo. L'ultimo livello in cui le eccezioni non devono mai sfuggire (ad es. Controller in un'app Web) dovrebbe essere quello che registra l'errore in quel caso.
duffymo,

Sono l'unico che trova assurdo che un registro non sia generato automaticamente per me? Sembra che tutti noi dobbiamo scrivere lo stesso stupido messaggio di log ogni volta che un pezzo di codice potrebbe generare un'eccezione.
ArtOfWarfare il

10

Un'alternativa più chiara (ma meno dettagliata, e forse non come preferita) alla risposta di user454322 su Java 6 (cioè Android) sarebbe quella di catturare tutti Exceptioni messaggi di lancio RuntimeException. Questo non funzionerebbe se stai pianificando di catturare altri tipi di eccezioni più in alto nello stack (a meno che tu non le rilasci anche loro), ma catturerà effettivamente tutte le eccezioni verificate .

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 verbosità, potrebbe essere meglio impostare un valore booleano o un'altra variabile e in base a quello eseguire un codice dopo il blocco try-catch.


1
Questo approccio impedisce al compilatore di determinare se sarà possibile o meno un "blocco catch".
the_new_mr

3

In pre-7 che ne dici di:

  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.
  }

3
sarà una bella soluzione. Che ne dici di inserire il controllo finale di caughtin un finallyblocco?
Andrea_86,

Ciò richiede più righe rispetto alla domanda originale.
Leandro Glossman,

1

Sì. Ecco come usare il separatore pipe (|),

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

Cos'è questo stile di codice? Il blocco catch in un blocco try?
Sam,

1

Per kotlin, per ora non è possibile ma hanno considerato di aggiungerlo: Fonte
Ma per ora, solo un piccolo trucco:

try {
    // code
} catch(ex:Exception) {
    when(ex) {
        is SomeException,
        is AnotherException -> {
            // handle
        }
        else -> throw ex
    }
}

0

Cattura l'eccezione che risulta essere una classe genitore nella gerarchia delle eccezioni. Questa è ovviamente una cattiva pratica . Nel tuo caso, l'eccezione genitore comune sembra essere la classe Exception e catturare qualsiasi eccezione che sia un'istanza di Exception, è in effetti una cattiva pratica: eccezioni come NullPointerException sono in genere errori di programmazione e dovrebbero essere risolte controllando i valori null.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.