2010-07-08 1 views
59

Qual è la regola generale per decidere se aggiungere una clausola di tiri a un metodo o utilizzare un try-catch?Lancia o prova + cattura

Da quello che ho letto io stesso, i lanci dovrebbero essere usati quando il chiamante ha rotto la loro fine del contratto (oggetto passato) e il try-catch deve essere usato quando un'eccezione avviene durante un'operazione che viene effettuato all'interno del metodo. È corretto? Se sì, cosa dovrebbe essere fatto dal lato dei chiamanti?

P.S: cercato tramite Google e SO, ma vorrei una risposta chiara su questo.

+3

Sono sempre stato un fan di "Se ha senso affrontarlo qui ... poi farlo". – CheesePls

+0

Mi piace che tutte le mie eccezioni vengano gestite dove si verificano, quindi non devo occuparmi del resto della strada. –

risposta

43
  • cattura un'eccezione solo se si può gestire in modo significativo
  • dichiarare gettare l'eccezione verso l'alto se deve essere maneggiato da parte del consumatore del metodo attuale
  • generano eccezioni se sono causati dai parametri di input (ma questi sono più spesso incontrollato)
+0

Giusto, la terza regola è molto chiara. A proposito di gestire un'eccezione in modo significativo, è presente nei livelli più alti di un programma? Ciò significa che le API tendono generalmente a generare eccezioni? Inoltre, in quali casi un metodo dovrebbe rilanciare le eccezioni provenienti dai submethods (provenienti da metodi di utilità privati, ad esempio)? –

+0

beh, dipende in gran parte. Le API generano eccezioni, sì. Ma poi arriva la scelta di spuntata vs deselezionata. – Bozho

+3

Perché rilanciare l'eccezione? Basta non prenderlo e passarlo sullo stack delle chiamate. –

12

In generale, un metodo deve generare un'eccezione al relativo chiamante quando non è in grado di gestire localmente il problema associato. Per esempio. se il metodo deve leggere da un file con il percorso specificato, IOExceptions non può essere gestito localmente in modo ragionevole. Lo stesso vale per input non validi, aggiungendo che la mia scelta personale sarebbe quella di lanciare un'eccezione non controllata come IllegalArgumentException in questo caso.

E dovrebbe rilevare un'eccezione da un metodo chiamato se

  • è qualcosa che può essere gestito a livello locale (ad esempio, cercare di convertire una stringa di input a un numero, e se la conversione non riesce, è interamente valido per restituire invece un valore predefinito),
  • oppure non deve essere lanciato (ad esempio se l'eccezione proviene da un livello inferiore specifico per l'implementazione, i cui dettagli di implementazione non dovrebbero essere visibili al chiamante, ad esempio non lo faccio t voglio mostrare che il mio DAO usa Hibernate per la persistenza delle mie entità, quindi catturo localmente tutte le HibernateExceptions e le converto nei miei tipi di eccezione).
+0

Ok. Per riformulare, un'eccezione verrebbe generata quando una soluzione immediata non è possibile e alcune interazioni sono necessarie "sopra" per decidere cosa fare. Inoltre, un'eccezione non può essere ripubblicata se ha solo un "significato" tra un gruppo di classi e un'eccezione più generalizzata dovrebbe essere generata al suo posto per informare il chiamante che è necessaria l'attenzione. Suona più o meno giusto? –

+1

@James, più o meno :-) Se per "interazione" intendi chiedere l'intervento dell'utente, non è sempre necessario. Inoltre, invece di "più generalizzato" preferirei "diverso". Una ConnectionException definita dall'utente non è più generale di HibernateException. –

8

mia regola empirica personnal di ciò è semplice:

  • Posso gestirlo in modo significativo (aggiunto dal commento)? Quindi inserire il codice in try/catch. Gestendolo, voglio dire essere in grado di informare l'utente/recuperare da un errore o, in un senso più ampio, essere in grado di capire in che modo questa eccezione influisce sull'esecuzione del mio codice.
  • Altrove, buttarlo via

Nota: questo replys ora è un wiki comunità, sentitevi liberi di aggiungere ulteriori informazioni in

+6

Posso gestirlo * in modo significativo *. – Nivas

+2

Quali sono i criteri per decidere se è possibile gestire un'eccezione localmente? Si trova al livello in cui puoi effettivamente occuparti dell'eccezione e visualizzare un messaggio, ad esempio? –

+0

Buttarlo via è una cattiva idea. È meglio passare lo stack delle chiamate. –

2

Se il metodo in cui l'eccezione ottenuto sollevato ha una quantità sufficente di informazioni. per affrontarlo poi dovrebbe catturare, generare informazioni utili su ciò che è accaduto e quali dati sono stati elaborati.

+0

Scrivi sempre l'eccezione di errore in un file di registrazione o nella console. Stavo pensando a quest'ultima notte perché nel programma in realtà non potrai vedere la console vera e propria, quindi i tuoi errori non dovrebbero andare in un file di testo. Quindi come stampa e.printStackTrace(). Vado alla console quando eseguo il debug ma a che altro si può fare? –

6

Ecco il modo in cui lo uso:

Produce:

  • Si vuole solo il codice per fermare quando si verifica un errore.
  • Buono con i metodi soggetti a errori se determinati prerequisiti sono non soddisfatti.

Try-Catch:

  • Quando si desidera avere il programma comportarsi in modo diverso con diversi errori.
  • Ottimo se si desidera fornire significativi errori agli utenti finali.

Conosco un sacco di persone che usano sempre i lanci perché è più pulito, ma non c'è quasi altrettanto controllo.

+0

Non si dovrebbe quasi mai usare la gestione delle eccezioni per il controllo del programma. È una pratica terribile. – CheesePls

+2

C'è anche Try-catch-rethrow, o try-catch-wrap-throw - cioè, solo perché puoi gestire l'eccezione in modo significativo non significa che hai finito. Il metodo dovrebbe fare ciò che il nome indica che farà o dovrebbe generare un'eccezione: http://abstractions-r-us.blogspot.com/2010/06/do-your-work-or-throw-exception-example. html. (plug spudorato per il mio blog) – apollodude217

+1

Questa è una domanda che mi stavo chiedendo da tempo. Penso di provare a utilizzare i blocchi try-catch, se necessario, con eccezioni definite dall'utente. Eccezione. Ma dovrò dire che un lancio del metodo è molto più pulito e molto meno codice da dover passare in seguito se si deve fare il debug. Se usi uno stub nel metodo, devi intrappolare l'errore nella catena di metodi, penso, non ne sono sicuro. Con un try-catch puoi semplicemente fare in modo che il try-catch cogli l'errore senza dover passare la catena dei metodi. Non sono completamente sicuro su questo, ma penso che –

3

La decisione di aggiungere una clausola try-catch o throws ai metodi dipende "come si desidera (o si ha) per gestire l'eccezione".

Come gestire un'eccezione è una domanda ampia e tutt'altro che semplice da rispondere. Implica in particolare la decisione su dove gestire l'eccezione e quali azioni implementare all'interno del blocco catch. In effetti, come gestire un'eccezione dovrebbe essere una decisione di progettazione globale.

Quindi, rispondendo alle vostre domande, non esiste una regola generale.

È necessario decidere dove si desidera gestire l'eccezione e tale decisione è in genere molto specifica per il dominio e i requisiti dell'applicazione.

1

Un metodo dovrebbe solo throws un'eccezione se può fornire garanzie ragionevoli sullo stato dell'oggetto, sui parametri passati al metodo e su qualsiasi altro oggetto su cui il metodo agisce. Ad esempio, un metodo che dovrebbe recuperare da una raccolta un elemento che il chiamante si aspetta che sia contenuto al suo interno potrebbe throws un'eccezione verificata se l'elemento che era previsto esistere nella raccolta, non lo fa. Un chiamante che cattura tale eccezione dovrebbe aspettarsi che la raccolta non contenga l'oggetto in questione.

Si noti che, mentre Java consentirà il controllo delle eccezioni a causa di un metodo che viene dichiarato come eccezioni di lancio dei tipi appropriati, tale utilizzo dovrebbe generalmente essere considerato un anti-pattern. Immaginiamo, ad esempio, che un metodo LookAtSky() sia dichiarato come chiamante FullMoonException, e si supponga che lo lanci quando la Luna è piena; Immaginiamo inoltre che LookAtSky() chiami ExamineJupiter(), che è anche dichiarato come throws FullMoonException. Se un è stato lanciato da ExamineJupiter(), e se LookAtSky() non lo ha catturato e lo gestisce o lo avvolge in qualche altro tipo di eccezione, il codice che ha chiamato LookAtSky assumerebbe l'eccezione era il risultato della luna piena della Terra; non avrebbe idea che una delle lune di Giove potrebbe essere il colpevole.

Le eccezioni che un chiamante può prevedere di gestire (incluse essenzialmente tutte le eccezioni controllate) devono essere autorizzate solo a risalire attraverso un metodo se l'eccezione significherà la stessa cosa per il chiamante del metodo in quanto ha significato per il metodo chiamato. Se il codice chiama un metodo che viene dichiarato come l'esecuzione di alcune eccezioni verificate, ma il chiamante non si aspetta che lanci quella eccezione in pratica (ad esempio perché pensa che siano argomenti del metodo pre-validati), l'eccezione verificata dovrebbe essere catturata e spostata in qualche tipo di eccezione non controllata. Se il chiamante non si aspetta che l'eccezione venga lanciata, il chiamante non può aspettarsi che abbia un significato particolare.

0

Se si utilizza un try catch, quando si verifica l'eccezione, i codici rimanenti verranno comunque eseguiti.

Se si indica il metodo per generare l'eccezione, quando si verifica l'eccezione, il codice non viene più eseguito immediatamente.

Problemi correlati