2010-08-23 17 views
40

Esistono linee guida sulla propagazione delle eccezioni in Java?Linee guida sulla propagazione delle eccezioni (in Java)

Quando si aggiunge un'eccezione alla firma del metodo? Ad esempio: se un'eccezione viene lanciata solo quando manca una risorsa di programma essenziale e può essere gestita solo al livello superiore, la propagare attraverso tutti i metodi utilizzando questa eccezione attraverso tutti i metodi che utilizzano il metodo erring?

Esistono buone pratiche? Qualche cattiva pratica?

Mi dispiace se sono vago, ma sto solo cercando alcuni consigli (generali) sullo stile di programmazione riguardante le eccezioni.

risposta

52

linee guida che mi hanno aiutato in passato includono:

  • generano eccezioni quando il metodo non è in grado di gestire l'eccezione, e ancora più importante, dovrebbe essere gestita dal chiamante. Un buon esempio di ciò è presente nell'API Servlet: doGet() e doPost() generano ServletException o IOException in determinate circostanze in cui la richiesta non può essere letta correttamente. Nessuno di questi metodi è in grado di gestire l'eccezione, ma il contenitore è (il che risulta nella pagina di errore 50x nella maggior parte dei casi).
  • Bubble l'eccezione se il metodo non può gestirlo. Questo è un corollario di quanto sopra, ma applicabile ai metodi che devono catturare l'eccezione. Se l'eccezione rilevata non può essere gestita correttamente con il metodo, è preferibile farlo bollire.
  • Eliminare immediatamente l'eccezione. Questo potrebbe sembrare vago, ma se si verifica uno scenario di eccezione, è buona norma lanciare un'eccezione che indichi il punto di errore originale, invece di tentare di gestire l'errore tramite i codici di errore, fino a un punto ritenuto idoneo a lanciare l'eccezione . In altre parole, tentare di minimizzare la gestione delle eccezioni di missaggio con la gestione degli errori.
  • Registrare l'eccezione o evidenziarla, ma non eseguire entrambe le operazioni. La registrazione di un'eccezione indica spesso che lo stack di eccezioni è stato completamente svolto, a indicare che non si sono verificati ulteriori bubbling dell'eccezione. Pertanto, non è consigliabile eseguire entrambi allo stesso tempo, poiché spesso comporta un'esperienza frustrante nel debug.
  • Utilizzare sottoclassi di java.lang.Exception (eccezioni controllate), tranne il chiamante per gestire l'eccezione. Ciò comporta che il compilatore genera un messaggio di errore se il chiamante non gestisce l'eccezione. Attenzione però, questo di solito porta gli sviluppatori a "inghiottire" le eccezioni nel codice.
  • Utilizzare sottoclassi di java.lang.RuntimeException (eccezioni non selezionate) per segnalare errori di programmazione. Le classi di eccezioni qui raccomandate includono IllegalStateException, IllegalArgumentException, UnsupportedOperationException ecc. Di nuovo, si deve fare attenzione sull'uso di classi di eccezioni come NullPointerException (quasi sempre una cattiva pratica per lanciarne una).
  • Utilizzare le gerarchie di classi di eccezioni per comunicare informazioni su eccezioni su vari livelli. Implementando una gerarchia, è possibile generalizzare il comportamento di gestione delle eccezioni nel chiamante. Ad esempio, è possibile utilizzare un'eccezione di root come DomainException che ha diverse sottoclassi come InvalidCustomerException, InvalidProductException ecc. L'avvertenza qui è che la gerarchia delle eccezioni può esplodere molto rapidamente se si rappresenta ogni scenario eccezionale separato come eccezione separata.
  • Evitare di rilevare eccezioni che non è possibile gestire. Piuttosto ovvio, ma molti sviluppatori tentano di catturare java.lang.Exception o java.lang.Throwable. Poiché tutte le eccezioni sottoclasse possono essere rilevate, il comportamento di runtime dell'applicazione può essere spesso vago quando vengono rilevate classi di eccezioni "globali". Dopo tutto, uno non vorrebbe prendere OutOfMemoryError - come si dovrebbe gestire una tale eccezione?
  • Avvolgere le eccezioni con cura. Il richiamo di un'eccezione resetta lo stack delle eccezioni. A meno che la causa originale non sia stata fornita al nuovo oggetto di eccezione, è persa per sempre. Per preservare lo stack delle eccezioni, sarà necessario fornire l'oggetto di eccezione originale al costruttore della nuova eccezione.
  • Convertire le eccezioni controllate in quelle deselezionate solo quando richiesto. Quando si avvolge un'eccezione, è possibile avvolgere un'eccezione controllata e lanciarne una non selezionata. Questo è utile in certi casi, specialmente quando l'intenzione è di interrompere il thread attualmente in esecuzione. Tuttavia, in altri scenari questo può causare un po 'di dolore, perché i controlli del compilatore non vengono eseguiti. Pertanto, l'adattamento di un'eccezione controllata come non controllata non è pensato per essere eseguito alla cieca.
+4

Non sono d'accordo che i dettagli vengono persi quando un'eccezione viene riconsegnata. –

+0

@Thorbjorn, ah si. Non abbastanza caffeina :-) Ho riformulato l'ultima sezione per riflettere la reale intenzione. –

+0

@VineetReynolds "Utilizzare sottoclassi di java.lang.Exception (eccezioni controllate), quando si esclude il chiamante per gestire l'eccezione" - intendevi "aspettarti"? – gumkins

2

È necessario gestire il metodo il prima possibile, ma deve avere senso. Se l'eccezione non ha senso essere lanciata dal metodo, ma non è possibile gestirla, avvolgerla in un'altra eccezione e lanciare questa nuova eccezione.

Una cattiva pratica di eccezione è catturarli tutti (non è pokemon, è java!), Quindi evitare catch(Exception e) o peggio catch(Throwable t).

+0

Cosa intendi con "avvolgere in un'altra eccezione"? Perché non solo ri-lanciare l'eccezione originale? – wen

+0

@Dennetik, in java devi catturare le eccezioni controllate o dichiararle per essere lanciate. Porta inevitabilmente ad avvolgere (o deglutire, che è una brutta cosa). Altrimenti la lista dei tiri diventa fuori controllo o ti imbatti in un'interfaccia che non ti permette di lanciare eccezioni controllate. – Yishai

+2

Perché a volte semplicemente rilanciare l'eccezione originale non ha senso, ad esempio se gestisci una connessione a un database per ottenere un'entità, e lancia una SQLException, non vuoi davvero rilanciare una SQLException, ma piuttosto una delle tue eccezioni, che ha senso nel tuo codice. –

Problemi correlati