Il modo moderno di eseguire la gestione degli errori ...


118

Sto riflettendo su questo problema da un po 'di tempo e mi ritrovo a trovare continuamente avvertimenti e contraddizioni, quindi spero che qualcuno possa produrre una conclusione su quanto segue:

Favorire eccezioni rispetto ai codici di errore

Per quanto ne sappia, dal lavorare nel settore per quattro anni, leggere libri e blog, ecc. L'attuale best practice per la gestione degli errori è generare eccezioni, piuttosto che restituire codici di errore (non necessariamente un codice di errore, ma un digitare che rappresenta un errore).

Ma - per me questo sembra contraddire ...

Codifica per interfacce, non implementazioni

Codifichiamo interfacce o astrazioni per ridurre l'accoppiamento. Non conosciamo o vogliamo sapere il tipo specifico e l'implementazione di un'interfaccia. Quindi, come possiamo sapere quali eccezioni dovremmo cercare di catturare? L'implementazione potrebbe generare 10 diverse eccezioni o non generare alcuna. Quando prendiamo un'eccezione sicuramente facciamo ipotesi sull'implementazione?

A meno che - l'interfaccia abbia ...

Specifiche di eccezione

Alcuni linguaggi consentono agli sviluppatori di affermare che determinati metodi generano determinate eccezioni (Java, ad esempio, utilizza la throwsparola chiave). Dal punto di vista del codice chiamante questo sembra a posto - sappiamo esplicitamente quali eccezioni potremmo dover catturare.

Ma questo sembra suggerire un ...

Astrazione che perde

Perché un'interfaccia dovrebbe specificare quali eccezioni possono essere generate? Cosa succede se l'implementazione non deve generare un'eccezione o deve generare altre eccezioni? Non è possibile, a livello di interfaccia, sapere quali eccezioni un'implementazione potrebbe voler generare.

Così...

Concludere

Perché le eccezioni sono preferite quando sembrano (ai miei occhi) contraddire le migliori pratiche del software? E, se i codici di errore sono così male (e non ho bisogno di essere venduti sui vizi dei codici di errore), c'è un'altra alternativa? Qual è lo stato dell'arte attuale (o che sarà presto) per la gestione degli errori che soddisfa i requisiti delle migliori pratiche come indicato sopra, ma non si basa sulla chiamata del codice che controlla il valore di ritorno dei codici di errore?


12
Non capisco la tua discussione su astrazioni che perdono. La specifica dell'eccezione che un particolare metodo può generare fa parte delle specifiche dell'interfaccia . Proprio come il tipo del valore restituito fa parte delle specifiche dell'interfaccia. Le eccezioni non "escono dal lato sinistro" della funzione, ma fanno ancora parte dell'interfaccia.
Ingannare

@deceze In che modo un'interfaccia può eventualmente indicare ciò che un'implementazione può lanciare? Potrebbe generare tutte le eccezioni nel sistema dei tipi! E che molte lingue non supportano le specifiche delle eccezioni suggeriscono che sono piuttosto ingannevoli
RichK

1
Concordo sul fatto che può essere complicato gestire tutte le diverse eccezioni che un metodo può generare, se esso stesso utilizza altri metodi e non rileva le loro eccezioni internamente. Detto questo, non è una contraddizione.
Ingannare

1
L'assunto che perde qui è che il codice può gestire un'eccezione quando sfugge al limite dell'interfaccia. È molto improbabile, dato che non sa abbastanza su cosa sia andato storto. Tutto quello che sa è che qualcosa è andato storto e l'implementazione dell'interfaccia non sapeva come gestirla. Le probabilità che possa fare un lavoro migliore sono scarse, oltre a segnalarlo e terminare il programma. O ignorarlo se l'interfaccia non è fondamentale per il corretto funzionamento del programma. Un dettaglio di implementazione che non puoi e non dovresti codificare in un contratto di interfaccia.
Hans Passant,

Risposte:


31

Prima di tutto, non sarei d'accordo con questa affermazione:

Favorire eccezioni rispetto ai codici di errore

Questo non è sempre il caso: ad esempio, dai un'occhiata a Objective-C (con il framework Foundation). Lì NSError è il modo preferito di gestire gli errori, nonostante l'esistenza di ciò che uno sviluppatore Java chiamerebbe vere eccezioni: @try, @catch, @throw, classe NSException, ecc.

Tuttavia è vero che molte interfacce perdono le loro astrazioni con le eccezioni generate. Ritengo che ciò non sia dovuto allo stile "d'eccezione" di propagazione / gestione degli errori. In generale, credo che il miglior consiglio sulla gestione degli errori sia questo:

Gestire l'errore / eccezione al livello più basso possibile, punto

Penso che se ci si attiene a quella regola empirica, la quantità di "fuoriuscita" dalle astrazioni può essere molto limitata e contenuta.

Se le eccezioni generate da un metodo debbano far parte della sua dichiarazione, credo che dovrebbero: fanno parte del contratto definito da questa interfaccia: questo metodo fa A o fallisce con B o C.

Ad esempio, se una classe è un parser XML, una parte della sua progettazione dovrebbe essere quella di indicare che il file XML fornito è semplicemente sbagliato. In Java, normalmente lo fai dichiarando le eccezioni che prevedi di incontrare e aggiungendole alla throwsparte della dichiarazione del metodo. D'altra parte, se uno degli algoritmi di analisi fallisce, non c'è motivo di passare l'eccezione sopra non gestita.

Tutto si riduce a una cosa: un buon design dell'interfaccia. Se si progetta l'interfaccia abbastanza bene, nessuna quantità di eccezioni dovrebbe perseguitarti. Altrimenti, non sono solo le eccezioni a disturbarti.

Inoltre, penso che i creatori di Java abbiano avuto ragioni di sicurezza molto forti per includere eccezioni a una dichiarazione / definizione di metodo.

Un'ultima cosa: alcune lingue, ad esempio Eiffel, hanno altri meccanismi per la gestione degli errori e semplicemente non includono funzionalità di lancio. Lì, un''eccezione 'di tipo viene sollevata automaticamente quando una postcondizione per una routine non è soddisfatta.


12
+1 per la negazione di "Favorire eccezioni rispetto ai codici di errore". Mi è stato insegnato che le eccezioni sono buone e buone, purché siano, in realtà, eccezioni e non la regola. Chiamare un metodo che genera un'eccezione per determinare se una condizione è vera è una pratica estremamente negativa.
Neil,

4
@JoshuaDrake: ha sicuramente torto. Eccezioni e gotosono molto diverse. Ad esempio, le eccezioni vanno sempre nella stessa direzione verso il basso dello stack di chiamate. In secondo luogo, proteggersi da eccezioni a sorpresa è esattamente la stessa pratica di DRY, ad esempio in C ++, se si utilizza RAII per garantire la pulizia, quindi garantisce la pulizia in tutti i casi, non solo l'eccezione, ma anche tutti i normali flussi di controllo. Questo è infinitamente più affidabile. try/finallyrealizza qualcosa di simile. Quando si garantisce correttamente la pulizia, non è necessario considerare le eccezioni come un caso speciale.
DeadMG

4
@JoshuaDrake Siamo spiacenti, ma Joel è molto lontano. Le eccezioni non sono le stesse di goto, si sale sempre almeno di un livello nello stack di chiamate. E cosa fai se il livello sopra non è in grado di gestire immediatamente il codice di errore? Restituisci ancora un altro codice di errore? Parte del problema con l'errore è che POSSONO essere ignorati, portando a problemi peggiori rispetto al lancio di un'eccezione.
Andy,

25
-1 perché non sono completamente d'accordo con "Gestisci l'errore / eccezione al livello più basso possibile" - è sbagliato, punto. Gestire errori / eccezioni al livello appropriato . Molto spesso si tratta di un livello molto più elevato e, in tal caso, i codici di errore sono un enorme dolore. Il motivo per favorire le eccezioni rispetto ai codici di errore è che consentono di scegliere liberamente a quale livello gestirli senza influire sui livelli intermedi.
Michael Borgwardt,

2
@Giorgio: vedi artima.com/intv/handcuffs.html - in particolare le pagine 2 e 3.
Michael Borgwardt,

27

Vorrei solo notare che le eccezioni e i codici di errore non sono l'unico modo per gestire errori e percorsi di codice alternativi.

Dall'alto della mente, puoi avere un approccio come quello adottato da Haskell, in cui gli errori possono essere segnalati tramite tipi di dati astratti con più costruttori (pensa enumerazioni discriminate o puntatori null, ma typesafe e con la possibilità di aggiungere sintattici funzioni di zucchero o di aiuto per rendere buono il flusso del codice).

func x = do
    a <- operationThatMightFail 10
    b <- operationThatMightFail 20
    c <- operationThatMightFail 30
    return (a + b + c)

operationThatMightfail è una funzione che restituisce un valore racchiuso in un Maybe. Funziona come un puntatore nullable, ma la notazione do garantisce che l'intera cosa venga valutata nulla se una delle a, b o c fallisce. (e il compilatore ti protegge dal creare una NullPointerException accidentale)

Un'altra possibilità è passare un oggetto gestore degli errori come argomento aggiuntivo a ogni funzione chiamata. Questo gestore di errori ha un metodo per ogni possibile "eccezione" che può essere segnalato dalla funzione a cui lo si passa e può essere utilizzato da quella funzione per trattare le eccezioni in cui si verificano, senza dover necessariamente riavvolgere lo stack tramite eccezioni.

LISP comune lo fa e lo rende fattibile con il supporto sintatico (argomenti impliciti) e facendo in modo che le funzioni integrate seguano questo protocollo.


1
È davvero pulito. Grazie per aver risposto alla parte sulle alternative :)
RichK,

1
A proposito, le eccezioni sono una delle parti più funzionali dei moderni linguaggi imperativi. Le eccezioni formano una monade. Le eccezioni usano la corrispondenza dei picchiettini. Le eccezioni aiutano a imitare lo stile applicativo senza effettivamente imparare ciò che Maybeè.
9000,

Di recente stavo leggendo un libro su SML. Ha citato tipi di opzioni, eccezioni (e continuazioni). Il consiglio era di usare tipi di opzioni quando si prevede che il caso indefinito si verifichi piuttosto spesso e di usare eccezioni quando il caso indefinito si verifica molto raramente.
Giorgio,

8

Sì, le eccezioni possono causare astrazioni che perdono. Ma i codici di errore non sono nemmeno peggiori in questo senso?

Un modo per affrontare questo problema è fare in modo che l'interfaccia specifichi esattamente quali eccezioni possono essere generate in quali circostanze e dichiarano che le implementazioni devono mappare il loro modello interno di eccezione a questa specifica, catturando, convertendo e rilanciando eccezioni se necessario. Se vuoi un'interfaccia "perfetta", questa è la strada da percorrere.

In pratica, di solito è sufficiente specificare le eccezioni che sono logicamente parte dell'interfaccia e su cui un client potrebbe voler catturare e fare qualcosa. Resta generalmente inteso che possono esserci altre eccezioni quando si verificano errori di basso livello o si manifesta un bug e che un client può gestire in generale solo mostrando un messaggio di errore e / o chiudendo l'applicazione. Almeno l'eccezione può ancora contenere informazioni che aiutano a diagnosticare il problema.

In effetti, con i codici di errore, praticamente accade la stessa cosa, solo in un modo più implicito e con una probabilità molto maggiore di perdere informazioni e l'app che finisce in uno stato incoerente.


1
Non capisco perché un codice di errore possa causare un'astrazione che perde. Se viene restituito un codice di errore anziché un normale valore restituito e questo comportamento è descritto nelle specifiche della funzione / metodo, allora IMO non presenta perdite. O sto trascurando qualcosa?
Giorgio,

Se il codice di errore è specifico dell'implementazione mentre l'API dovrebbe essere indipendente dall'implementazione, la specifica e la restituzione del codice di errore perdono i dettagli dell'implementazione indesiderata. Esempio tipico: un'API di registrazione con un'implementazione basata su file e basata su DB, in cui la prima potrebbe contenere un errore "disco pieno" e la seconda un errore "Connessione DB rifiutata dall'host".
Michael Borgwardt,

Capisco cosa intendi. Se si desidera segnalare errori specifici dell'implementazione, l'API non può essere indipendente dall'implementazione (né con codici di errore né con eccezioni). Immagino che l'unica soluzione sia quella di definire un codice di errore indipendente dall'implementazione come "risorsa non disponibile" o di decidere che l'API non sia indipendente dall'implementazione.
Giorgio,

1
@Giorgio: Sì, la segnalazione di errori specifici dell'implementazione è complicata da un'API indipendente dall'implementazione. Tuttavia, puoi farlo con eccezioni, perché (a differenza dei codici di errore) possono avere più campi. Quindi è possibile utilizzare il tipo di eccezione per fornire le informazioni di errore generico (ResourceMissingException) e includere un codice / messaggio di errore specifico dell'implementazione come campo. Il meglio di entrambi i mondi :-).
sleske,

E a proposito, questo è proprio quello che fa java.lang.SQLException. Ha getSQLState(generico) e getErrorCode(specifico del fornitore). Ora, se solo avesse avuto delle sottoclassi adeguate ...
sleske,

5

Un sacco di cose buone qui, vorrei solo aggiungere che dovremmo tutti stare attenti al codice che utilizza le eccezioni come parte del normale flusso di controllo. A volte le persone entrano in quella trappola in cui tutto ciò che non è il solito caso diventa un'eccezione. Ho anche visto un'eccezione utilizzata come condizione di terminazione del loop.

Le eccezioni significano "qualcosa che non riesco a gestire qui è successo, è necessario rivolgersi a qualcun altro per capire cosa fare". Un utente che digita input non validi non è un'eccezione (che dovrebbe essere gestito localmente dall'input chiedendo di nuovo, ecc.).

Un altro caso degenerato di utilizzo delle eccezioni che ho visto sono le persone la cui prima risposta è "gettare un'eccezione". Questo è quasi sempre fatto senza scrivere il fermo (regola empirica: scrivi prima il fermo, poi la dichiarazione di lancio). In applicazioni di grandi dimensioni questo diventa problematico quando un'eccezione non rilevata viene fuori dalle regioni inferiori e fa esplodere il programma.

Non sono anti-eccezioni, ma sembrano dei singoletti di qualche anno fa: usati troppo spesso e in modo inappropriato. Sono perfetti per l'uso previsto, ma quel caso non è così ampio come alcuni pensano.


4

Astrazione che perde

Perché un'interfaccia dovrebbe specificare quali eccezioni possono essere generate? Cosa succede se l'implementazione non deve generare un'eccezione o deve generare altre eccezioni? Non è possibile, a livello di interfaccia, sapere quali eccezioni un'implementazione potrebbe voler generare.

No. Le specifiche delle eccezioni si trovano nello stesso bucket dei tipi restituiti e di argomento: fanno parte dell'interfaccia. Se non è possibile conformarsi a tale specifica, non implementare l'interfaccia. Se non lanci mai, allora va bene. Non c'è nulla che permetta di specificare le eccezioni in un'interfaccia.

I codici di errore vanno ben oltre. Sono terribili. Devi ricordare manualmente di controllarli e propagarli, ogni volta, per ogni chiamata. Ciò viola DRY, per cominciare, e fa esplodere in modo massiccio il codice di gestione degli errori. Questa ripetizione è un problema molto più grande di qualsiasi altra eccezione. Non puoi mai ignorare silenziosamente un'eccezione, ma le persone possono ignorare silenziosamente i codici di ritorno, sicuramente una cosa negativa.


I codici di errore possono essere più facili da usare se si hanno buone forme di zucchero sintetico o metodi di aiuto, e in alcune lingue è possibile fare in modo che il compilatore e il sistema di tipi garantiscano che non dimenticherete mai di gestire un codice di errore. Per quanto riguarda la parte dell'interfaccia delle eccezioni, penso che stesse pensando alla famigerata goffaggine delle eccezioni controllate di Java. Mentre a prima vista sembrano un'idea perfettamente ragionevole, in pratica causano molti piccoli dolorosi problemi.
hugomg,

@missingno: Questo perché, come al solito, Java ne ha una terribile implementazione, non perché le eccezioni verificate siano intrinsecamente cattive.
DeadMG

1
@missingno: quali tipi di problemi possono essere causati da eccezioni controllate?
Giorgio,

@Giorgio: è molto difficile prevedere ogni tipo di eccezione che potrebbe essere lanciata da un metodo, dal momento che questo deve tener conto di altre sottoclassi e codici che devono ancora essere scritti. In pratica le persone finiscono con brutte soluzioni che gettano via informazioni, come riutilizzare una classe di eccezioni di sistema per tutto o dover catturare e rigettare frequentemente eccezioni interne. Ho anche sentito che le eccezioni verificate erano un grosso ostacolo quando cercavano di aggiungere funzioni anonime alla lingua.
hugomg,

@missingno: le funzioni anonime AFAIK in Java sono solo zucchero sintattico per le classi interne anonime con esattamente un metodo, quindi non sono sicuro di capire perché le eccezioni verificate sarebbero un problema (ma ammetto di non sapere molto sull'argomento). Sì, è difficile prevedere quali eccezioni genererà un metodo, ecco perché IMO può essere utile avere verificato le eccezioni, in modo da non dover indovinare. Ovviamente puoi scrivere codice scadente per gestirli, ma puoi farlo anche con eccezioni non controllate. Tuttavia, so che il dibattito è piuttosto complesso e onestamente vedo pro e contro in entrambe le parti.
Giorgio,

2

Bene, la gestione delle eccezioni può avere una propria implementazione dell'interfaccia. A seconda del tipo di eccezione generata, eseguire i passaggi desiderati.

La soluzione al tuo problema di progettazione è avere due implementazioni di interfaccia / astrazione. Uno per la funzionalità e l'altro per la gestione delle eccezioni. E a seconda del tipo di eccezione rilevata, chiamare la classe del tipo di eccezione appropriata.

L'implementazione dei codici di errore è un modo ortodosso di gestire le eccezioni. È come l'uso di string vs. string builder.


4
in altre parole: le implementazioni generano sottoclassi delle eccezioni definite nell'API.
Andrew Cooke,

2

Le eccezioni IM-very-HO devono essere giudicate caso per caso, poiché interrompendo il flusso di controllo aumenteranno la complessità effettiva e percepita del codice, in molti casi inutilmente. Mettere da parte la discussione relativa al lancio di eccezioni all'interno delle funzioni - che può effettivamente migliorare il flusso di controllo, se si desidera esaminare il lancio di eccezioni attraverso i limiti di chiamata, considerare quanto segue:

Consentire a una chiamata di interrompere il flusso di controllo potrebbe non fornire alcun vantaggio reale e potrebbe non esserci un modo significativo per gestire l'eccezione. Per un esempio diretto, se si sta implementando il modello osservabile (in un linguaggio come C # in cui si hanno eventi ovunque e non si è espliciti throwsnella definizione), non vi è alcun motivo effettivo per consentire all'Osservatore di interrompere il flusso di controllo in caso di crash e nessun modo significativo di gestire le loro cose (ovviamente, un buon vicino non dovrebbe lanciare quando osserva, ma nessuno è perfetto).

L'osservazione sopra può essere estesa a qualsiasi interfaccia liberamente accoppiata (come hai sottolineato); Penso che in realtà sia una norma che dopo aver insinuato 3-6 stack frame, un'eccezione non rilevata rischia di finire in una sezione di codice che:

  • è troppo astratto per gestire l'eccezione in qualsiasi modo significativo, anche se l'eccezione stessa viene annullata;
  • sta eseguendo una funzione generica (non potrebbe importare di meno del motivo per cui hai fallito, come un pump dei messaggi o l'osservabile);
  • è specifico, ma con una diversa responsabilità e non dovrebbe davvero preoccuparsi;

Considerando quanto sopra, decorare le interfacce con la throwssemantica è solo un guadagno funzionale marginale, perché molti chiamanti attraverso i contratti di interfaccia si preoccuperebbero solo in caso di fallimento, non perché.

Direi che diventa una questione di gusto e convenienza: il tuo obiettivo principale è recuperare con grazia il tuo stato sia nel chiamante che nella chiamata dopo una "eccezione", quindi, se hai molta esperienza nel spostare i codici di errore (coming da uno sfondo C), o se stai lavorando in un ambiente in cui le eccezioni possono diventare malvagie (C ++), non credo che gettare roba in giro sia così importante per OOP bello e pulito che non puoi fare affidamento sul tuo vecchio schemi se non ti senti a tuo agio. Soprattutto se porta alla rottura del SoC.

Da una prospettiva teorica, penso che un modo kosher di SoC di gestire le eccezioni possa essere derivato direttamente dall'osservazione che il più delle volte il chiamante si preoccupa solo del tuo fallimento, non del perché. La chiamata lancia, qualcuno molto vicino sopra (2-3 frame) cattura una versione upcast, e l'eccezione effettiva viene sempre affondata a un gestore di errori specializzato (anche se solo per tracciare) - qui è dove AOP sarebbe utile, perché questi gestori sono probabilmente orizzontali.


1

Favorire eccezioni rispetto ai codici di errore

  • Entrambi dovrebbero coesistere.

  • Restituisce il codice di errore quando si prevede un determinato comportamento.

  • Restituisci un'eccezione quando non hai previsto un comportamento.

  • I codici di errore sono normalmente associati a un singolo messaggio, quando rimane il tipo di eccezione, ma un messaggio può variare

  • L'eccezione ha una traccia dello stack, quando il codice di errore no. Non uso codici di errore per eseguire il debug del sistema danneggiato.

Codifica per interfacce non implementazioni

Questo potrebbe essere specifico per JAVA, ma quando dichiaro le mie interfacce non specifico quali eccezioni potrebbero essere generate da un'implementazione di tale interfaccia, semplicemente non ha senso.

Quando prendiamo un'eccezione sicuramente facciamo ipotesi sull'implementazione?

Questo dipende interamente da te. Puoi provare a individuare un tipo di eccezione molto specifico e quindi prendere un tipo più generale Exception. Perché non lasciare che l'eccezione si propaghi nello stack e quindi gestirlo? In alternativa puoi guardare la programmazione degli aspetti in cui la gestione delle eccezioni diventa un aspetto "collegabile".

Cosa succede se l'implementazione non deve generare un'eccezione o deve generare altre eccezioni?

Non capisco perché sia ​​un problema per te. Sì, potresti avere un'implementazione che non fallisce mai o genera eccezioni e potresti avere un'implementazione diversa che fallisce costantemente e genera eccezioni. In tal caso, non specificare alcuna eccezione sull'interfaccia e il problema è stato risolto.

Cambierebbe qualcosa se invece di eccezione l'implementazione restituisse un oggetto risultato? Questo oggetto conterrebbe il risultato della tua azione insieme a eventuali errori / insuccessi. È quindi possibile interrogare quell'oggetto.


1

Astrazione che perde

Perché un'interfaccia dovrebbe specificare quali eccezioni possono essere generate? Cosa succede se l'implementazione non deve generare un'eccezione o deve generare altre eccezioni? Non è possibile, a livello di interfaccia, sapere quali eccezioni un'implementazione potrebbe voler generare.

Nella mia esperienza, il codice che riceve l'errore (sia esso tramite eccezione, codice di errore o qualsiasi altra cosa) normalmente non si preoccuperebbe della causa esatta dell'errore - reagirebbe allo stesso modo di qualsiasi errore, tranne che per l'eventuale segnalazione del errore (che si tratti di una finestra di dialogo di errore o di un tipo di registro); e questa segnalazione verrebbe fatta ortogonalmente al codice che chiamava la procedura fallita. Ad esempio, questo codice potrebbe passare l'errore ad un altro pezzo di codice che sa come segnalare errori specifici (ad esempio formattare una stringa di messaggio), eventualmente allegando alcune informazioni di contesto.

Naturalmente, in alcuni casi è necessario associare una semantica specifica agli errori e reagire in modo diverso in base all'errore che si è verificato. Tali casi dovrebbero essere documentati nelle specifiche dell'interfaccia. Tuttavia, l'interfaccia può ancora riservarsi il diritto di generare altre eccezioni senza un significato specifico.


1

Trovo che le eccezioni consentano di scrivere un codice più strutturato e conciso per la segnalazione e la gestione degli errori: l'utilizzo dei codici di errore richiede il controllo dei valori di ritorno dopo ogni chiamata e la decisione su cosa fare in caso di risultati imprevisti.

D'altro canto, sono d'accordo sul fatto che le eccezioni rivelano dettagli di implementazione che dovrebbero essere nascosti al codice che invoca un'interfaccia. Poiché non è possibile sapere a priori quale parte del codice può generare quali eccezioni (a meno che non siano dichiarate nella firma del metodo come in Java), utilizzando le eccezioni stiamo introducendo dipendenze implicite molto complesse tra le diverse parti del codice, che è contro il principio di minimizzare le dipendenze.

riassumendo:

  • Penso che le eccezioni consentano un codice più pulito e un approccio più aggressivo ai test e al debug perché le eccezioni non rilevate sono molto più visibili e difficili da ignorare rispetto ai codici di errore (falliscono presto).
  • D'altra parte, i bug di eccezione non rilevati che non vengono rilevati durante il test possono apparire in un ambiente di produzione sotto forma di crash. In determinate circostanze questo comportamento non è accettabile e in questo caso penso che l'utilizzo di codici di errore sia un approccio più solido.

1
Non sono d'accordo. Sì, le eccezioni non rilevate possono causare l'arresto anomalo di un'applicazione, ma anche i codici di errore non controllati possono essere eliminati. Se usi le eccezioni correttamente, le uniche non rilevate saranno quelle fatali (come OutOfMemory), e per queste, il crash immediato è il meglio che puoi fare.
sleske,

Il codice di errore fa parte del contratto tra il chiamante m1 e la chiamata m2: i possibili codici di errore sono definiti solo nell'interfaccia di m2. Con le eccezioni (a meno che tu non stia utilizzando Java e dichiari tutte le eccezioni generate nelle firme dei metodi) hai un contratto implicito tra il chiamante m1 e tutti i metodi che possono essere chiamati da m2, in modo ricorsivo. Quindi ovviamente è un errore non controllare un codice di errore restituito, ma è sempre possibile farlo. D'altra parte, non è sempre possibile controllare tutte le eccezioni generate da un metodo, a meno che non si sappia come viene implementato.
Giorgio,

Primo: puoi controllare tutte le eccezioni - fai semplicemente "Gestione delle eccezioni di Pokemon" (devi prenderle tutte - cioè catch Exceptiono anche Throwable, o equivalente).
sleske,

1
In pratica, se l'API è stata progettata correttamente, specificherà tutte le eccezioni che il client può gestire in modo significativo, queste devono essere individuate in modo specifico. Questi sono gli equivalenti dei codici di errore). Qualsiasi altra eccezione significa "errore interno" e l'applicazione dovrà chiudere o almeno chiudere il sottosistema corrispondente. Puoi prenderli se vuoi (vedi sopra), ma di solito dovresti semplicemente lasciarli scoppiare. Quel "gorgogliamento" è il principale vantaggio dell'uso delle eccezioni. Puoi ancora prenderli più in alto, o meno, a seconda delle esigenze.
sleske,

-1

Sia di parte destra.

Non può essere ignorato, deve essere gestito, è completamente trasparente. E se usi il tipo di errore mancino corretto, trasmette tutte le stesse informazioni di un'eccezione Java.

Svantaggio? Il codice con una corretta gestione degli errori sembra disgustoso (vero per tutti i meccanismi).


ciò non sembra offrire nulla di sostanziale rispetto ai punti formulati e spiegati nelle precedenti 10 risposte. Perché sbattere due anni fa con cose del genere
moscerino il

Tranne nessuno qui menzionato neanche il giusto distorto. hugomg si è avvicinato parlando di haskell, tuttavia forse è un gestore di errori di merda in quanto non lascia alcuna spiegazione del motivo per cui si è verificato l'errore, né alcun metodo diretto con cui recuperare, e le richiamate sono uno dei più grandi peccati nella progettazione del flusso di controllo. E questa domanda è arrivata su google.
Keynan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.