Domanda

Ho del codice che fornisce un ID utente a un'utilità che quindi invia un'e-mail a quell'utente.

emailUtil.sendEmail(userId, "foo");

public void sendEmail(String userId, String message) throws MailException {
    /* ... logic that could throw a MailException */
}

MailException potrebbe essere lanciato per una serie di motivi, problemi con l'indirizzo email, problemi con il modello di posta ecc.

La mia domanda è questa:crei un nuovo tipo di eccezione per ognuna di queste eccezioni e poi le gestisci individualmente oppure crei una MailException e quindi memorizzi qualcosa nell'eccezione (qualcosa di leggibile dal computer, non il testo della descrizione) che ci consente di fare cose diverse in base a ciò che è realmente accaduto.

Modificare: A titolo di chiarimento, le eccezioni non riguardano i log e quant'altro, ma si riferiscono al modo in cui il codice reagisce ad essi.Per continuare con l'esempio della posta, diciamo che quando inviamo la posta, l'operazione potrebbe fallire perché non disponi di un indirizzo email, oppure potrebbe fallire perché non hai un indirizzo email valido indirizzo email, altrimenti potrebbe fallire..eccetera.

Il mio codice vorrebbe reagire in modo diverso a ciascuno di questi problemi (principalmente modificando il messaggio restituito al client, ma anche la logica effettiva).

Sarebbe meglio avere un'implementazione di eccezioni per ciascuno di questi problemi o un'eccezione ombrello che contenga qualcosa di interno (diciamo un'enumerazione) che consenta al codice di distinguere che tipo di problema si tratta.

È stato utile?

Soluzione

Di solito inizio con un'eccezione generale e la sottoclasso secondo necessità.Posso sempre cogliere l'eccezione generale (e con essa tutte le eccezioni sottoclassate) se necessario, ma anche quella specifica.

Un esempio dell'API Java è IOException, che ha sottoclassi come FileNotFoundException o EOFException (e molto altro).

In questo modo ottieni i vantaggi di entrambi, non hai clausole di lancio come:

throws SpecificException1, SpecificException2, SpecificException3 ...

un generale

throws GeneralException

è abbastanza.Ma se vuoi avere una reazione speciale a circostanze speciali puoi sempre cogliere l’eccezione specifica.

Altri suggerimenti

Nel mio codice, trovo che la MAGGIOR PARTE delle eccezioni filtra fino a un livello dell'interfaccia utente dove vengono catturate dai miei gestori di eccezioni che visualizzano semplicemente un messaggio all'utente (e scrivono nel registro).Dopotutto è un'eccezione inaspettata.

A volte, voglio rilevare un'eccezione specifica (come sembra che tu voglia fare).Probabilmente scoprirai, tuttavia, che questo è piuttosto raro e che è indicativo dell'uso delle eccezioni per controllare la logica, il che è inefficiente (lento) e spesso disapprovato.

Quindi, utilizzando il tuo esempio, se desideri eseguire una logica speciale quando il server di posta elettronica non è configurato, potresti voler aggiungere un metodo all'oggetto emailUtil come:

public bool isEmailConfigured()

...chiamalo prima, invece di cercare un'eccezione specifica.

Quando si verifica un'eccezione, significa in realtà che la situazione era completamente inaspettata e il codice non è in grado di gestirla, quindi la cosa migliore che puoi fare è segnalarla all'utente (o scriverla in un log o riavviare)

Per quanto riguarda la gerarchia delle eccezioni rispetto alle eccezioni con codici di errore, di solito faccio quest'ultima opzione.È più semplice aggiungere nuove eccezioni, se hai solo bisogno di definire una nuova costante di errore invece di una classe completamente nuova.Ma non importa finché cerchi di essere coerente durante tutto il tuo progetto.

@Chris.Vivace

Sai che puoi passare un messaggio nella tua eccezione o anche i "codici di stato".Stai reinventando la ruota qui.

Ho scoperto che se è necessario che CODE decida cosa fare in base all'eccezione restituita, creare un'eccezione ben denominata che sottoclassi un tipo base comune.Il messaggio trasmesso dovrebbe essere considerato “solo occhi umani” e troppo fragile per prendere decisioni.Lascia che il compilatore faccia il lavoro!

Se è necessario passare questo a un livello superiore attraverso un meccanismo che non riconosce le eccezioni controllate, è possibile racchiuderlo in una sottoclasse denominata adeguata di RuntimeException (MailDomainException) che può essere rilevata e la causa originale può essere utilizzata.

Dipende da cosa sta facendo la tua applicazione.Potresti voler lanciare eccezioni individuali in casi come

  • L'applicazione è ad alta disponibilità
  • L'invio di e-mail è particolarmente importante
  • L'ambito dell'applicazione è limitato e l'invio di e-mail ne costituisce una parte importante
  • L'applicazione verrà distribuita su un sito remoto e riceverai solo i registri per il debug
  • È possibile eseguire il ripristino da alcuni sottoinsiemi delle eccezioni incapsulate in mailException ma non da altre

Nella maggior parte dei casi direi semplicemente di registrare il testo dell'eccezione e di non perdere tempo a granularizzare eccezioni già piuttosto granulari.

Penso che una combinazione di quanto sopra ti darà il miglior risultato.

Puoi generare eccezioni diverse a seconda del problema.per esempio.Indirizzo e-mail mancante = ArgumentException.

Ma poi nel livello dell'interfaccia utente è possibile verificare il tipo di eccezione e, se necessario, il messaggio e quindi visualizzare un messaggio appropriato all'utente.Personalmente tendo a mostrare un messaggio informativo all'utente solo se viene generato un certo tipo di eccezione (UserException nella mia app).Ovviamente dovresti pulire e verificare l'input dell'utente il più possibile più in alto nello stack per assicurarti che eventuali eccezioni siano generate da scenari veramente improbabili, non come filtro per e-mail non valide che possono essere facilmente controllate con una regex.

Inoltre, non mi preoccuperei delle implicazioni sulle prestazioni derivanti dall'acquisizione di un'eccezione dall'input dell'utente.L'unica volta in cui vedrai problemi di prestazioni dalle eccezioni è quando vengono lanciate e catturate in un loop o simili.

Invece di utilizzare le eccezioni, tendo a restituire un elenco di oggetti di stato da metodi che potrebbero avere problemi di esecuzione.Gli oggetti di stato contengono un'enumerazione di gravità (informazioni, avviso, errore, ...), un nome di oggetto di stato come "Indirizzo e-mail" e un messaggio leggibile dall'utente come "Indirizzo e-mail formattato in modo errato"

Il codice chiamante deciderà quindi quale filtrare fino all'interfaccia utente e quale gestire autonomamente.

Personalmente, penso che le eccezioni servano esclusivamente quando non è possibile implementare una normale soluzione di codice.Il calo delle prestazioni e le restrizioni di manovrabilità sono un po' eccessive per me.

Un altro motivo per utilizzare un elenco di oggetti di stato è che identificare più errori (come durante la convalida) è MOLTO più semplice.Dopotutto, puoi lanciare solo un'eccezione che deve essere gestita prima di procedere.

Immagina che un utente invii un'e-mail con un indirizzo di destinazione non valido e una lingua che stai bloccando.Si lancia l'eccezione di posta elettronica non valida e, dopo averla risolta e inviata nuovamente, si lancia un'eccezione di linguaggio volgare?Dal punto di vista dell'esperienza dell'utente, affrontarli tutti contemporaneamente è un modo migliore di procedere.

AGGIORNAMENTO: combinando le risposte

@Jonathan:Il punto era che posso valutare l'azione, in questo caso inviando un'e-mail, e rispedire più motivi di errore.Ad esempio, "indirizzo email errato", "titolo del messaggio vuoto", ecc.

Con un'eccezione, ti limiti a filtrare semplicemente l'unico problema e poi a chiedere all'utente di inviarlo nuovamente, a quel punto scopre un secondo problema.Questo è un design dell'interfaccia utente davvero pessimo.

Reinventare la ruota..possibilmente.Tuttavia, la maggior parte delle applicazioni dovrebbe analizzare l'intera transazione per fornire all'utente le migliori informazioni possibili.Immagina se il tuo compilatore si fermasse al primo errore.Quindi correggi l'errore e premi nuovamente la compilazione solo per interromperlo di nuovo per un errore diverso.Che dolore al sedere.Per me, questo è esattamente il problema con la generazione di eccezioni e quindi il motivo per cui ho detto di utilizzare un meccanismo diverso.

Tendo ad avere meno tipi di eccezioni, anche se non è proprio il modo OO per farlo.Invece inserisco un'enumerazione nelle mie eccezioni personalizzate, che classifica l'eccezione.La maggior parte delle volte ho un'eccezione di base personalizzata, che mantiene un paio di membri, che possono essere sovrascritti o personalizzati nei tipi di eccezione derivati.

Un paio di mesi fa I bloggato sull’idea di come internazionalizzare le Eccezioni.Include alcune delle idee sopra menzionate.

Sebbene sia possibile differenziare l'esecuzione del codice osservando l'eccezione, non importa se viene eseguita tramite la "modalità gerarchia catchExceptionType" o tramite "if(...) else...exception code mode"

ma se stai sviluppando un software che verrà utilizzato da altre persone, come una libreria, penso che sia utile creare i tuoi tipi di eccezioni per notare alle altre persone che il tuo software può generare eccezioni diverse da quelle normali, ed è meglio che catturino e risolverli.

Quando utilizzo una libreria e i suoi metodi lanciano semplicemente un''eccezione', mi chiedo sempre:Cosa può causare questa eccezione?, come deve reagire il mio programma?, se c'è un javadoc forse la causa verrà spiegata, ma molte volte non c'è un javadoc o l'eccezione non viene spiegata.È possibile evitare un sovraccarico eccessivo con un WellChossenExceptionTypeName

Dipende se il codice che rileva l'eccezione deve distinguere tra eccezioni o se si stanno semplicemente utilizzando le eccezioni per eseguire il failout su una pagina di errore.Se devi distinguere tra un'eccezione NullReference e la tua MailException personalizzata più in alto nello stack di chiamate, dedica tempo e scrivila.Ma la maggior parte delle volte i programmatori usano semplicemente le eccezioni come cattura tutto per generare un errore nella pagina web.In questo caso stai solo sprecando energie scrivendo una nuova eccezione.

Vorrei semplicemente passare

throw new exception("WhatCausedIt")

se vuoi gestire le tue eccezioni, potresti passare un codice invece di "WhatCausedIt" e poi reagire alle diverse risposte con un'istruzione switch.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top