2013-10-03 7 views
23

Questo è molto strano per me. RuntimeException eredita da Exception, che eredita da Throwable.Perché non rileva Exception catch RuntimeException?

catch(Exception exc) { /* won't catch RuntimeException */ 

ma

catch(Throwable exc) { /* will catch RuntimeException */ 

so RuntimeException è speciale in quanto è incontrollato. Ma per quanto ne so, si applica solo per stabilire se devono essere dichiarate le eccezioni, e non se vengono catturate. E anche allora, non so perché questa logica si rompa con la cattura di Throwable.

Questo è abbastanza importante per me poiché ho una situazione in cui RuntimeExceptions può essere generata in un'operazione terminale. Non sono sicuro del nome di questo modello, ma qualcosa del genere, la mia classe EmailRoller accetta un array di Callbacks. Il codice è simile al seguente:

for(Callback cb : callbacks) { 
    try { 
     cb.call(item); 
    } 
    catch(Exception exc) { 
     logger.error("Error in callback: ", exc); 
    } 
} 

Quindi questo è un caso in cui qualcosa come un OOME ha bisogno di volare attraverso, perché se uno di questi callback consuma tutta la memoria della macchina, che sicuramente come diamine sta andando ad incidere l'esecuzione di gli altri. Ma uno NullPointerException? O un IndexOutOfBoundsException? Quelli influenzeranno la richiamata ma non impediranno l'esecuzione degli altri.

Inoltre, questo è un po 'un design aziendale. Diversi programmatori o team possono aggiungere callback per elaborare l'articolo, ma dovrebbero essere isolati l'uno dall'altro. Ciò significa che, poiché il programmatore è responsabile dell'isolamento reciproco di questi callback, non dovrei fare affidamento su di essi per evitare errori. La cattura Exception dovrebbe essere sulla linea giusta, ma non è perché RuntimeException scivola attraverso. Quindi la mia domanda più generale è: qual è un buon modello qui? Solo catch(Exception | RuntimeException exc), che credo sia un errore di sintassi a causa dell'ereditarietà?

risposta

81

La premessa della domanda è errata, perché la cattura di Exceptionfa cattura RuntimeException. Codice Demo:

public class Test { 
    public static void main(String[] args) { 
     try { 
      throw new RuntimeException("Bang"); 
     } catch (Exception e) { 
      System.out.println("I caught: " + e); 
     } 
    } 
} 

uscita:

I caught: java.lang.RuntimeException: Bang 

il ciclo avrà problemi se:

  • callbacks è nullo
  • nulla modifica callbacks mentre il ciclo è in esecuzione (se fosse una raccolta piuttosto che un array)

Forse è questo che stai vedendo?

+2

Rileggere il mio codice. È corretto. Il mio livello di isolamento era buggato, poiché l'eccezione di runtime proveniva da un 'if (results.foo.bar()) {/ * applica callback * /}', che era un NPE. – djechlin

+6

@djechlin: Il tuo post non mostra * 'if (results.foo.bar())' - non è molto chiaro cosa stai chiedendo a questo punto ... –

18
catch (Exception ex) { ... } 

WILL cattura RuntimeException.

Qualsiasi cosa venga inserita nel blocco di cattura verrà catturata come pure nelle sottoclassi di esso.

7

Facendo Exception prenderà una RuntimeException

2

ho affrontato scenario simile.Stava succedendo perché l'inizializzazione di classA dipendeva dall'inizializzazione di classB. Quando il blocco statico di ClassB ha riscontrato un'eccezione di runtime, la classe B non è stata inizializzata. Per questo motivo, classB non ha generato eccezioni e anche l'inizializzazione di classA ha avuto esito negativo.

class A{//this class will never be initialized because class B won't intialize 
    static{ 
    try{ 
     classB.someStaticMethod(); 
    }catch(Exception e){ 
     sysout("This comment will never be printed"); 
    } 
} 
} 

class B{//this class will never be initialized 
static{ 
    int i = 1/0;//throw run time exception 
} 

public static void someStaticMethod(){} 
} 

E sì ... la cattura Exception cattura eccezioni fase di esecuzione pure.