2010-03-10 14 views

risposta

47

Perché quando rilevi l'eccezione devi gestirlo correttamente. E non puoi aspettarti di gestire tutti i tipi di eccezioni nel tuo codice. Inoltre, quando rilevi tutte le eccezioni, puoi ottenere un'eccezione che non può gestire e impedire che il codice sia in cima allo stack per gestirlo correttamente.

Il principio generale è catturare il tipo più specifico possibile.

+9

Ad esempio java.lang.InterruptedException viene sollevata quando un thread viene richiesto di fermarsi. Se rilevato e ignorato, l'elaborazione del thread non può essere interrotta con garbo e il codice diventa improprio per essere eseguito in un thread di lavoro. Questo è un esempio, potrebbero essercene altri. – Pierre

+1

Sono un grande fan delle persone che comprendono i loro quadri. La ragione principale per cui questo consiglio è terribile è che il 90% delle volte il codice che le persone scrivono per la gestione delle eccezioni si trova al limite della loro API. Sono d'accordo che all'interno di un'API, dovresti sempre rilevare le eccezioni appropriate, ma quando sei a un limite API, ti preghiamo di prendere tutto ciò che non uccide il sistema. – coding

5

Perché non si sa davvero perché si è verificata un'eccezione e diverse eccezioni richiedono che un'auto molto speciale venga gestita correttamente (se possibile), come ad esempio OutOfMemoryException e simili eccezioni di sistema di basso livello.

Pertanto, si deve solo rilevare le eccezioni:

  • che si sa esattamente come trattare con esso (ad esempio FileNotFoundException o giù di lì)
  • quando si re-raise in seguito (ad esempio per effettuare il post cleanup -fail)
  • quando è necessario trasportare l'eccezione di un altro thread
+0

Non esiste OutOfMemoryException. C'è OutOfMemoryError che si trova sotto la gerarchia Throwable. –

+2

@EladTabak, hai ragione ovviamente riguardo a Java. Detto questo, il tag "java" non era lì quando ho risposto alla domanda (vedi [cronologia revisioni] (http://stackoverflow.com/posts/2416316/revisions)), e il significato trasmesso è nondimeno corretto - indipendentemente da l'ambiente reale. – Lucero

5

dipende da quello che vi serve. Se è necessario gestire diversi tipi di eccezioni in modi diversi, è necessario utilizzare più blocchi catch e catturare tutte le eccezioni specifiche possibili.

Ma a volte potrebbe essere necessario gestire tutte le eccezioni allo stesso modo. In questi casi, catch (Exception) potrebbe essere ok. Ad esempio:

try 
    { 
     DoSomething(); 
    } 
    catch (Exception e) 
    { 
     LogError(e); 
     ShowErrorMessage(e); // Show "unexpected error ocurred" error message for user. 
    } 
+2

Non è un buon schema da seguire; la registrazione non dovrebbe essere fatta in questo modo perché otterrai un sacco di voci uguali per ogni "livello" di try-catch. – Lucero

+0

Sono d'accordo, l'ho usato solo come esempio. Potrebbe non essere l'esempio migliore :) –

+1

@Lucero: Penso che sarebbe meglio disporre di un framework di registrazione in grado di consolidare le voci ridondanti, piuttosto che presupporre che qualsiasi livello gestisca (swallow) un'eccezione lo registrerà. Inoltre, a meno che le eccezioni siano così numerose che registrarle più volte potrebbe comportare un collo di bottiglia nelle prestazioni (nel qual caso direi * che è * un problema che deve essere risolto), penserei di avere informazioni ridondanti nel log, che potrebbero essere filtrate da Un'utilità di visualizzazione dei registri, sarebbe preferibile avere un registro più conciso che manca l'unica informazione di cui si ha bisogno. – supercat

8

È necessario rilevare eccezioni solo se è possibile gestirle correttamente. Dato che non puoi gestire correttamente tutte le possibili eccezioni, non dovresti prenderle :-)

+8

Un grosso problema con questo modo di pensare è che ci sono molte situazioni in cui la corretta gestione del 99% delle eccezioni che potrebbero essere generate potrebbe essere quella di segnalare che alcune azioni non possono essere completate e andare avanti con la vita, ma identificando ogni singolo il tipo di eccezione per cui quella sarebbe la giusta linea di condotta sarebbe difficile se non impossibile. Peccato che non ci sia alcun meccanismo per distinguere le eccezioni di "could not soddisfare la richiesta" da "CPU in fiamme". – supercat

+1

La CPU è in fiamme probabilmente causerà una sorta di 'java.lang.Error'. – yegeniy

+0

> Un errore è una sottoclasse di Throwable che indica i problemi seri che un'applicazione ragionevole non dovrebbe provare a catturare. – yegeniy

15

Breve storia: si chiama bug masking. Se hai un pezzo di codice che non funziona bene e genera eccezioni (o passi input malformati a quel pezzo di codice) e accechi solo gli occhi catturando tutte le possibili eccezioni, in realtà non scoprirai mai il bug e lo sistemerai.

+0

"Catching" un'eccezione non significa solo continuare l'esecuzione come se non ci fosse nulla di sbagliato. Un blocco "catch" è un blocco di codice in cui si fa ** qualcosa **. Quel ** qualcosa **, potrebbe essere quello di registrare le informazioni sull'eccezione, su ciò che l'utente stava facendo o lo stato dell'interfaccia utente, per chiudere connessioni e file in modo che l'app possa uscire con garbo, e per notificare all'utente cosa è successo. Come è questo "mascherare" qualcosa? – user316117

+0

@ user316117 'Exception' è la prima classe di tutte le eccezioni in Java. Cattura che significa che prendi tutti i possibili errori. Come sapresti cosa fare in un simile blocco? Se vuoi reagire a un determinato errore, prendi la sua eccezione specifica e lavoraci. Non serve praticamente a cogliere tutte le eccezioni possibili tranne che accecare i propri occhi (e ho visto molti colleghi farlo perché vogliono tornare a casa alla fine della giornata lavorativa). – dimitarvp

+0

@dimitarvp Throwable è di prima classe di tutte le eccezioni. Ha due sottoclassi che separano le eccezioni in due rami. Uno di questi è EXCEPTION e l'altro è ERROR. –

0

Questo può essere specifica Java:

A volte è necessario chiamare i metodi che gettano eccezioni controllate. Se questo è nel livello EJB/business logic hai 2 scelte: prendile o rilancia.

La rilevazione di classi di eccezioni specifiche implica la necessità di analizzare nuovamente le azioni per le quali è possibile generare eccezioni quando si cerca di vedere come questo codice gestisce le eccezioni. Spesso entrerai in una situazione di "che cosa succede se ..." e può essere molto impegnativo lavorare solo se le eccezioni vengono gestite correttamente.

Rilanciare significa che il codice che chiama il tuo EJB sarà pieno di codice che in genere non significa nulla per la classe chiamante. N.B. lanciando eccezioni controllate dai metodi EJB significa che sei responsabile del ripristino manuale delle transazioni.

0

Oltre a ciò che ancora risposto da @anthares:

Perché quando si cattura un'eccezione si suppone di gestire in modo corretto. E non puoi aspettarti di gestire tutti i tipi di eccezioni nel tuo codice. Inoltre, quando rilevi tutte le eccezioni, puoi ottenere un'eccezione che non può gestire e impedire che il codice sia in cima allo stack per gestirlo correttamente.

Il principio generale è catturare il tipo più specifico possibile.

catch(Exception) è una cattiva pratica perché cattura anche tutti i RuntimeException (eccezione non controllata).

0

Ma a volte è OK! Come se avessi un pezzo di codice che fa qualcosa di "extra", di cui non ti interessa davvero, e non vuoi che faccia esplodere la tua applicazione. Ad esempio, recentemente ho lavorato a una grande applicazione in cui i nostri partner commerciali desideravano che una determinata transazione giornaliera venisse riepilogata in un nuovo file di registro. Hanno spiegato che il registro non era tanto importante per loro, e che non era qualificato come requisito. Era solo qualcosa in più che li avrebbe aiutati a dare un senso ai dati elaborati. Non ne avevano bisogno, perché potevano ottenere le informazioni altrove. Quindi questo è un caso raro in cui è perfettamente corretto catturare e ingoiare le eccezioni.

Ho lavorato anche in un'azienda in cui sono stati catturati tutti i Throwables e quindi ripubblicato all'interno di una RuntimeException personalizzata. Non consiglierei questo approccio, ma solo sottolineando che è stato fatto.

0

Trovo due usi accettabili di cattura (eccezione): - Al livello più alto dell'applicazione (appena prima di tornare all'utente). In questo modo puoi fornire un messaggio adeguato. - Usalo per mascherare le eccezioni di basso livello a quelle aziendali.

Il primo caso è auto-esplicativo, ma mi permetta di sviluppare il secondo:

fare:

try { 
    xxxx 
} catch(Exception e) { 
    logger.error("Error XXX",e) 
} 

è bug mascheramento come @dimitarvp detto.

Ma

try { 
    xxxx 
} catch(Exception e) { 
    throw new BussinessException("Error doing operation XXX",e) 
} 

E 'una cosa diversa. In questo modo non stai ignorando bug e nascondendo sotto il tappeto. Stai fornendo un'eccezione di alto livello con un messaggio più esplicativo a livelli di applicazione più elevati.

E 'sempre importante anche due riescono eccezione al suo corretto livello. Se si lascia escalare un'eccezione di basso livello a un livello aziendale elevato è praticamente impossibile che il livello superiore possa gestirlo bene. In quei casi, preferisco mascherare i bassi livelli di eccezioni con un business quello che fornisce un contesto e il messaggio meglio e che ha anche l'eccezione originale di essere in grado di andare ai dettagli.

Anche così, se è possibile ottenere eccezioni più concrete e si può fornire un trattamento migliore per loro è necessario farlo.

Se in un blocco di codice è possibile ottenere SQLException e NetworkException, è necessario catturarli e fornire messaggi e trattamenti adeguati per ciascuno di essi. Ma se alla fine del blocco try/catch hai un'eccezione che la mappa con un BussinessException va bene per me. In effetti, ritengo adeguato che i livelli di servizio più elevati generino solo eccezioni aziendali (con dettagli all'interno).

Problemi correlati