Domanda

Ho affrontato casi in cui avrei gettare / rigenerare un'eccezione sapendo che il codice circostante sarebbe intercettare l'eccezione specifica. Ma c'è ogni volta che si vorrebbe un'eccezione, sapendo che non sarebbe stato catturato?

O, almeno, non rilevare un'eccezione?

Eccezioni fermare immediatamente la domanda se il loro gestito giusto? Quindi credo che mi sto chiedendo se si vorrebbe mai lasciare volutamente morire vostra applicazione?

È stato utile?

Soluzione

Se l'applicazione è in primo luogo sta per essere utilizzato da altri clienti e non è autonomo, in genere è di gettare le eccezioni se una condizione che si pone non si sa come (o non vuole) gestire, e non c'è modo sensato per recuperare da esso. I clienti dovrebbero essere in grado di decidere come vogliono gestire le eventuali eccezioni che si potrebbe buttare.

D'altra parte, se l'applicazione è il punto finale, un'eccezione diventa essenzialmente un meccanismo di notifica per avvisare le persone che qualcosa è andato terribilmente storto. In questi casi, è necessario considerare alcune cose:

  • Quanto è importante il continuo funzionamento dell'applicazione? È questo errore davvero irreversibile? un'eccezione e chiude il programma non è qualcosa che si vuole fare sulla navetta spaziale.

  • Stai usando le eccezioni come proxy per la registrazione vera e propria Non c'è quasi mai un motivo per fare questo?; considerare invece un vero meccanismo di registrazione. Intercettare l'eccezione e hanno il logger capire cosa è successo.

  • Che cosa stai cercando di trasmettere gettando eccezione te stesso? Chiedetevi che cosa il valore nel lanciare una nuova eccezione è, e considerare attentamente se non c'è un modo migliore per farlo ciò che si desidera.

  • Non cattura un'eccezione può lasciare risorse in cattivo stato. Se non si esce con grazia, le cose non sono generalmente puliti per voi. Assicurarsi di aver compreso quello che stai facendo, se avete bisogno di fare questo -. E se non avete intenzione di prenderlo, almeno prendere in considerazione un blocco try-finally in modo da poter fare un po 'mettere in ordine

Altri suggerimenti

C'è una buona regola che mi sono imbattuto in qualche tempo fa:

un'eccezione quando un metodo non può fare ciò che il suo nome dice fa.

L'idea è che un eccezione indica che qualcosa è andato storto. Quando si implementa un metodo, non è vostra responsabilità di essere a conoscenza di se verrà utilizzato correttamente o meno. Sia il codice utilizzando il metodo di cattura l'eccezione o no non è vostra responsabilità, ma la responsabilità della persona che utilizza il metodo.

Un'altra regola da seguire è:

Non rilevare un'eccezione a meno che non si sa cosa si vuole fare con esso.

Ovviamente, è necessario includere il codice di pulitura in un blocco try ... finally, ma non si dovrebbe mai solo rilevare un'eccezione solo per il gusto di catturare esso. E non si dovrebbe mai ingoiare eccezioni in silenzio. Mentre ci sono occasioni in cui si consiglia di prendere tutte le eccezioni (per esempio per fare catch (Exception ex) in C #), questi sono abbastanza rari e generalmente hanno una ben precisa ragione tecnica. Ad esempio, quando si utilizza thread in .NET 2.0 o versione successiva, se un'eccezione fugge dal tuo thread, causerà l'intero dominio applicazione da scaricare. In questi casi, tuttavia, come minimo si dovrebbe registrare i dettagli di eccezione come un errore e fornire una spiegazione nei commenti.

In generale, e certamente nelle prime iterazioni della vostra applicazione, non intercettare l'eccezione. Più spesso che no, il recupero da un'eccezione richiederà una regola aziendale di qualche tipo, e, il più delle volte, le regole di business non sono definiti per voi. Se "gestire" l'eccezione invece di lasciare morire l'applicazione allora si sarà molto probabilmente inventare le regole di business per il vostro cliente. Non va bene.

Lo schema generale di catturare ogni eccezione solo per il gusto di catturare mi ha causato più mal di testa che posso contare. Di solito succede che qualcuno mette una sorta di codice di gestione delle eccezioni generico in tutta l'applicazione, che finisce inevitabilmente per nascondere un bug o la creazione di un comportamento che è indesiderato. (Per inciso, la cattura e poi non rethrowing è ancora peggio.)

Quindi, io suggerirei che si chiede invece: "? Quando devo rilevare un'eccezione"

Certo. Ad esempio, se si sta cercando di caricare alcuni byte in una stringa in Java:

try {
  String myString = new String(byteArray, "UTF-8");
} catch (UnsupportedEncodingException e) {
  // Platform doesn't support UTF-8?  What is this, 1991?
  throw new RuntimeExceptione(e);
}

In questo caso, non v'è alcuna degradazione elegante, la piattaforma semplicemente non può sostenere l'operazione desiderata. È possibile verificare questa condizione al momento dell'inizializzazione tutto quello che volete, ma il costruttore di String getta ancora questa eccezione, e si hanno a che fare con esso. O che, o utilizzare Charset.forName ():)

Ecco la cosa ... si tratta di "strati" o "incapsulamento" o "basso accoppiamento". Ad un certo posto nel vostro codice di base, si sta scrivendo un metodo per fare qualcosa. Dicono che è un metodo pubblico. Pertanto, non dovrebbe assumere molto o nulla del chiamante ... piuttosto, dovrebbe limitarsi a fare il lavoro che dovrebbe fare, a prescindere da chi sta chiamando e quale contesto il chiamante è in.

E se, per qualche motivo, non si può completare il suo lavoro, quindi ha bisogno di dire al chiamante "Mi dispiace, non ho potuto farlo, ed ecco perché". Le eccezioni sono un ottimo meccanismo di lasciarlo dire al chiamante che (non l'unico meccanismo, ma il miglior meccanismo che abbia mai visto per la maggior parte dei casi).

Quindi, quando si getta l'eccezione, non si ha idea se sarà catturato o no ... perché si sta esponendo un metodo pubblico e non avete idea di chi potrebbe scegliere di chiamare e perché.

La cattura di eccezione è il lavoro del "contesto". Ad esempio, dire che si sta scrivendo una biblioteca con metodi pubblici che potrebbero generare eccezioni. Quindi, diciamo che si sta utilizzando quella libreria da un Windows Form app. Il Windows Form applicazione potrebbe intercettare le eccezioni e mostrare una finestra di messaggio per l'utente.

Ma in seguito, è possibile utilizzare la stessa libreria da un servizio di Windows. Il servizio sarebbe più in grado di attirare l'eccezione, log esso, restituire un errore al chiamante originale, ma continuare a correre in modo che possa elaborare le ulteriori richieste.

Quindi, l'eccezione è come un accordo contrattuale tra il chiamante e il fornitore. Il fornitore dice: "Io o fare il lavoro o che vi dica perché non posso. Quello che fai da lì è il proprio business." E il chiamante dice "OK, se non si può fare il lavoro, dimmi perché, e io deciderò cosa fare in questo caso."

  

Ma c'è qualche tempo si vorrebbe un'eccezione, sapendo che non sarebbe stato catturato?

Direi che se si sta gettando manualmente un'eccezione, il più delle volte non sai se sarà catturato. Se si sapeva che sarebbe stato catturato si può solo gestire da soli, piuttosto che gettare l'eccezione, in primo luogo.

Per essere onesti, credo che dipende in parte dal tipo di programmazione che si sta facendo, e talvolta lo stesso programmatore finisce per costruire sia la biblioteca e il codice che consuma detto biblioteca.

  

Hai mai non rilevare un'eccezione?

Se non ti aspettavi / non erano a conoscenza un'eccezione potrebbe essere gettati

. Ma mettendo da parte e supponendo che siete a conoscenza di eccezione, a volte si sa su di esso in una sola fila, ma si conosce il livello successivo up è il luogo più appropriato per gestire la cosa.

Dipende dal tipo di applicazione. Le applicazioni Web possono continuare a funzionare anche dopo che le eccezioni sono bolle fino al contesto di esecuzione.

E 'pratica comune 'tiro / rethrow' un'eccezione se si cattura l'eccezione ad un livello in cui non può essere affrontato. Ma, si sarebbe quasi sempre aggiungere contesto al problema, per lo meno aggiungere un po 'di registrazione a livello più alto di dire che è stato catturato e rilanciati.

per esempio

A chiama B chiama C (tiri eccezione)

B catture / genera nuovamente

A catture.

In questo caso, si vorrebbe B per aggiungere un po 'di registrazione in modo da poter distinguere tra la generazione B e gettando un errore, e di generazione C e gettando un errore. Ciò permetterà una maggiore capacità di eseguire il debug e risolvere i problemi in seguito.

In generale sarà quasi mai voglia un'eccezione per uccidere il vostro programma. La pratica migliore è quello di catturare l'eccezione e uscire con grazia. Questo ti permette di salvare tutte le informazioni attualmente aperto e liberare le risorse che vengono utilizzati in modo da non danneggiato. Se avete intenzione di uscire, è possibile creare il proprio rapporto di informazioni 'core-discarica' che include le cose che stavi facendo quando hai preso l'eccezione irreversibile.

Se si lascia che l'eccezione uccidere il processo che si sta eliminando la tua possibilità di ottenere su misura personalizzati informazioni incidente, e si sono anche saltando la parte in cui si fornisce l'utente con un messaggio di errore amichevole e poi uscire.

Quindi, mi sento di raccomandare sempre la cattura di eccezioni, e mai volontariamente permettendo loro impazziti nel vostro programma.

Modifica

Se si sta scrivendo una libreria, si deve scegliere in anticipo se la funzione sarà un'eccezione, o di essere al sicuro eccezione. In questi casi, a volte si genera un'eccezione e non hanno alcuna idea se il chiamante sarà prenderlo. Ma in questo caso, la cattura non è vostra responsabilità, a condizione che l'API dichiara che la funzione potrebbe generare eccezioni. (Sto cercando una parola che significa 'potrei eccezione tiro' ... qualcuno sa di cosa si tratta? E 'intenzione di bug me tutto il giorno.)

In primo luogo, ci sono assolutamente situazioni in cui è meglio non rilevare un'eccezione.

A volte, un'eccezione a volte può dirvi che il vostro programma è in uno stato sconosciuto. Ci sono un certo numero di eccezioni in cui questo è più o meno intrinsecamente vero dato il tipo di eccezione. Un NullReferenceException ti dice in sostanza, "c'è un bug". E per la cattura di una riserva del genere, si può nascondere il bug, che suona bene nel breve termine, ma nel lungo termine, saresti più felice di risolvere il problema. Il prodotto non può bloccare, ma certamente non avrà il comportamento previsto.

Ma questo è vero anche per i tipi di eccezione che inventiamo per noi stessi. A volte, il fatto che un'eccezione A è stato gettato dovrebbe essere "impossibile" -., Eppure è successo, quindi non c'è un bug

Inoltre, cosa molto importante accade quando si cattura un'eccezione: verranno eseguiti i finally blocchi per l'intero stack di chiamate all'interno del blocco try (e tutto ciò che chiama). Che significano quei blocchi finally fanno? Beh, qualsiasi cosa. E se il programma è in uno stato sconosciuto, io davvero dire niente . Essi potrebbero cancellare i dati dei clienti preziosi dal disco. Potrebbero lanciare più eccezioni. Essi potrebbero danneggiare i dati in memoria, rendendo il bug impossibile da diagnosticare.

Così, quando un'eccezione indica uno stato sconosciuto, non si vuole correre più codice, in modo da qualunque cosa tu faccia, non si cattura l'eccezione . Let it fly passato, e il programma terminerà innocuo, e Segnalazione errori di Windows sarà in grado di catturare lo stato del programma come lo era quando il problema è stato originariamente rilevato. Se si cattura l'eccezione, si causare più codice da eseguire, che rovinare lo stato del programma ulteriormente.

In secondo luogo, si dovrebbe lanciare un'eccezione sapendo che non sarà catturato? Credo che questa domanda fraintende la natura dei metodi riutilizzabili. L'intera idea di un metodo è che ha un "contratto" che ne consegue: accetta determinati parametri e restituisce un certo valore, più anche getta alcune eccezioni a determinate condizioni. Questo è il contratto - spetta al chiamante quello che fanno con esso. Per alcune chiamate, ad eccezione A potrebbe indicare una condizione recuperabile. Per gli altri chiamanti, potrebbe indicare un bug. E da quello che ho detto in precedenza, dovrebbe essere chiaro che se un eccezione indica un bug, si deve non essere catturati .

E se vi state chiedendo che cosa questo significa per il eccezione di Microsoft Enterprise Library Manipolazione Block : sì, è abbastanza rotto. Essi dicono di catch (Exception x) e quindi decidere se rigenerare in base alla politica; troppo tardi - le <=> blocchi hanno già eseguito da quel punto. Non farlo.

Probabilmente non vorrebbe un'eccezione non rilevata nessuna parte in cui gli utenti finali possono vedere, ma spesso è accettabile lasciare che i clienti del vostro API (altri programmatori) decidere come gestire le eccezioni.

Per esempio, supponiamo che si sta progettando una libreria di classi Java. Si espone un metodo pubblico che prende in una stringa. Nell'applicazione, un valore di ingresso nullo causerebbe un errore. Invece di gestire l'errore da soli, sarebbe accettabile per verificare la presenza di un valore nullo, poi gettare un IllegalArgumentException.

È necessario, naturalmente, documento che il vostro metodo genera questa eccezione in questa circostanza. Questo comportamento diventa parte del contratto del metodo.

Dipende da cosa si intende per 'essere catturati'. Qualcosa, da qualche parte alla fine cattura l'eccezione che si tratti del sistema operativo sottostante o qualcosa d'altro.

Abbiamo un sistema di flusso di lavoro che esegue piani di lavoro costituiti da singoli lavori. Ogni lavoro viene eseguito un'unità di codice. Per alcune delle eccezioni, non vogliamo per gestirli nel codice, ma gettarlo lo stack in modo che il sistema di workflow esterna afferra (il che accade completamente al di fuori del processo del lanciatore).

Se si scrive l'intera applicazione, quindi i vostri motivi sono proprio. Mi vengono in mente un paio di situazioni in cui si potrebbe voglio gettare l'eccezione e lasciar morire l'applicazione, la maggior parte di loro non sono molto buone ragioni però.

Il miglior motivo è di solito in fase di debug. Mi capita spesso di disattivare le eccezioni durante il debug per permettere a me di conoscere meglio dove qualcosa sta fallendo. È anche possibile attivare pause eccezione generata nel debugger se si sta eseguendo su una macchina con il debugger.

Un'altra possibile ragione è quando continuando dopo viene generata un'eccezione non ha senso o comporterebbe la corruzione dei dati recuperabili o peggio (si pensi robot con raggi laser, ma poi si dovrebbe essere dannatamente sicuro le vostre offerte applicaiton con queste situazioni IMO , crash il programma è solo il modo pigro).

Se si scrive il codice API, o il codice Framework che non utilizzerà te stesso, allora non avete idea se qualcuno prenderà le vostre eccezioni.

Yup, è la mia unica possibilità di schiaffeggiare lo sviluppatore consumando il servizio / oggetto di dire loro "Ur dO1n sbagliato !!!!".

Questo e sbarazzarsi di possibilità che non si desidera consentire o sono apparentemente "impossibile". Applicazioni che catturano tutte le eccezioni e continuare sono solo un giardino recintato circondato da caos.

Se ho bisogno di un moderatamente grande sistema che è in qualche modo elaborando i dati in quello che ritengo essere un modo coerente.

e

qualche parte lungo la linea, a rilevare che lo stato dell'applicazione è diventato incoerente.

e

Il sistema non fa (ancora) sanno come risolvere l'incoerenza e recuperare con grazia

Quindi, sì, avrei un'eccezione nel modo più dettagliato possibile e causare l'applicazione di morire il più velocemente possibile, per evitare di fare ulteriori danni ai dati. Se può essere recuperato, sarebbe importante non esacerbare il problema cercando debolmente di coprire il pasticcio.

In seguito lungo la linea, una volta che la catena di eventi che ha portato alla incoerenza è meglio compresa, ho maggiore facilità posso prendere tale eccezione, riparare lo Stato, e continuare con minima interruzione.

Una biblioteca spesso generare eccezioni sulla base di controlli di programmazione difensiva, dovrebbe sorgere una condizione che non avrebbe dovuto essere consentito a sorgere dal codice dell'applicazione. Applications sarà spesso scritto in modo tale che la maggior parte di queste condizioni non valide non potrà mai nascere, e non sarà mai gettato quindi le eccezioni, quindi non c'è nessun punto loro cattura.

A seconda lingua (Sono per lo più pensare in termini di C ++ piuttosto che C #, e non chiaro quali siano le differenze) l'effetto di un'eccezione non rilevata in realtà essere gettato probabilmente è lo stesso di quello usato per essere fatto in giorni prima eccezioni sono state inventate. Una politica comune per la programmazione difensiva librerie C, per esempio, era di risolvere immediatamente il programma con un messaggio di errore.

La differenza è che se il tiro eccezione non rivelarsi possibile (spero che questo sarà scoperto attraverso test di unità), spesso è relativamente facile aggiungere un gestore di eccezioni che può recuperare dal problema in modo più costruttivo. Non è necessario riscrivere la biblioteca, o aggiungere controlli complessi nel codice dell'applicazione per garantire la condizione non può nascere prima della chiamata eccezioni lancio è fatto.

Ho un bel po 'un'eccezione tiri che non vengono mai catturati. Sono tutti per scopi difensivi, e pur essendo non rilevata è un male per un'eccezione che fa accadere, questo sempre e solo accade durante lo sviluppo e la sperimentazione, per le condizioni di errore sono riuscito a prendere in considerazione nel codice dell'applicazione finora. E quando accade, è insolito per la correzione di essere imbarazzante - c'è bisogno di un refactoring su larga scala, non c'è bisogno per il codice delle applicazioni per essere massicciamente complicato con condizione di errore assegni, solo una clausola catch con un relativamente semplice recupero o " mi dispiace, Dave, temo di non poterlo fare ". senza fallire l'intera applicazione.

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