Argomenti a favore o contro l'utilizzo di Try / Catch come operatori logici [chiuso]

32

Ho appena scoperto un codice adorabile nella nostra app aziendale che utilizza i blocchi Try-Catch come operatori logici.
Significa, "fai un po 'di codice, se questo genera questo errore, fai questo codice, ma se questo genera questo errore fai questa terza cosa invece".
Usa "Finalmente" come l'affermazione "altro" che appare.
So che questo è sbagliato di per sé, ma prima di iniziare a litigare speravo in argomenti ben congegnati.
E hey, se hai argomenti PER l'uso di Try-Catch in questo modo, ti preghiamo di dirlo.

Per chi si sta chiedendo, la lingua è C # e il codice in questione è di circa 30+ linee e cerca eccezioni specifiche, non sta gestendo TUTTE le eccezioni.

    
posta James P. Wright 06.08.2014 - 22:27
fonte

15 risposte

48

La gestione delle eccezioni tende ad essere un costoso modo di gestire il controllo del flusso (certamente per C # e Java).

Il runtime fa un bel po 'di lavoro quando viene costruito un oggetto di eccezione: ottenere insieme lo stack trace, capire dove viene gestita l'eccezione e altro.

Tutto ciò comporta costi in memoria e risorse della CPU che non è necessario espandere se le istruzioni di controllo del flusso vengono utilizzate per il controllo del flusso.

Inoltre, c'è un problema semantico. Le eccezioni sono per situazioni eccezionali, non per il normale controllo del flusso. Si dovrebbe usare la gestione delle eccezioni per gestire situazioni impreviste / eccezionali, non come normali flussi di programma, perché altrimenti un'eccezione non rilevata vi dirà molto meno.

Oltre a questi due, c'è il problema degli altri che leggono il codice. L'utilizzo di eccezioni in questo modo non è qualcosa che la maggior parte dei programmatori si aspetteranno, quindi la leggibilità e la comprensibilità del tuo codice. Quando si vede "Eccezione", si pensa - è successo qualcosa di brutto, qualcosa che non dovrebbe accadere normalmente. Quindi, usare le eccezioni in questo modo è semplicemente fonte di confusione.

    
risposta data 23.10.2012 - 06:18
fonte
17

I just discovered some lovely code in our companies app that uses Try-Catch blocks as logical operators. Meaning, "do some code, if that throws this error, do this code, but if that throws this error do this 3rd thing instead". It uses "Finally" as the "else" statement it appears. I know that this is wrong inherently...

Come lo sai? Ho rinunciato a tutto questo tipo di "conoscenza" e ora credo solo che il codice più semplice sia il migliore. Supponiamo di voler convertire una stringa in un Opzionale, che è vuoto se l'analisi fallisce. Non c'è niente di sbagliato in:

try { 
    return Optional.of(Long.valueOf(s)); 
} catch (NumberFormatException) { 
    return Optional.empty(); 
}

Sono completamente in disaccordo con la solita interpretazione di "Le eccezioni sono per condizioni eccezionali". Quando una funzione non può restituire un valore utilizzabile o un metodo non può soddisfare le sue post-condizioni, genera un'eccezione. Non importa quante volte vengono lanciate queste eccezioni fino a quando non si verifica un problema prestazionale prestabilito.

Le eccezioni semplificano il codice, consentendo la separazione della gestione degli errori dal flusso normale. Basta scrivere il codice più semplice possibile, e se è più facile usare try-catch o lanciare un'eccezione, allora fallo.

Le eccezioni semplificano i test riducendo il numero di percorsi attraverso il codice. Una funzione senza rami completerà o genererà un'eccezione. Una funzione con più istruzioni if per verificare i codici di errore ha molti percorsi possibili. È molto facile ottenere una delle condizioni sbagliate o dimenticarne una completamente, in modo che alcune condizioni di errore vengano ignorate.

    
risposta data 22.02.2017 - 16:21
fonte
12

Il lavoro di debug e manutenzione è molto difficile quando viene eseguito il controllo del flusso utilizzando le eccezioni.

Inerentemente, le eccezioni sono progettate per essere un meccanismo per alterare il normale flusso di controllo del tuo programma - di eseguire attività insolite, causando insoliti effetti collaterali, come un modo per uscire da un legame particolarmente stretto che non può essere gestito con mezzi meno complicati. Le eccezioni sono eccezionali. Ciò significa che, a seconda del particolare ambiente in cui stai lavorando, l'uso di eccezioni per il controllo regolare del flusso può causare:

  • Inefficienza I cerchi aggiuntivi che l'ambiente deve attraversare per eseguire in sicurezza i cambiamenti di contesto relativamente difficili richiesti per le eccezioni richiedono strumentazione e risorse.

  • Difficoltà di debug A volte utili (quando si tenta di eseguire il debug di un programma) le informazioni vengono espulse dalla finestra quando si verificano eccezioni. Puoi perdere traccia dello stato o della cronologia del programma che è rilevante per la comprensione del comportamento in fase di esecuzione

  • Problemi di manutenzione Il flusso di esecuzione è difficile da seguire attraverso i salti di eccezioni. Oltre a ciò, un'eccezione potrebbe essere lanciata dal codice di tipo black-box, che potrebbe non comportarsi in modo facile da capire quando si lancia un'eccezione.

  • Decisioni di progettazione scarse I programmi costruiti in questo modo incoraggiano uno stato d'animo che, nella maggior parte dei casi, non si adatta facilmente alla soluzione dei problemi. La complessità del programma finale scoraggia il programmatore dal comprendere appieno la sua esecuzione e incoraggia a prendere decisioni che portano a miglioramenti a breve termine con costi elevati a lungo termine.

risposta data 12.09.2011 - 23:01
fonte
10

Ho visto questo pattern usato più volte.

Ci sono 2 problemi principali:

  • È estremamente costoso (creazione di istanze dell'oggetto di eccezione, raccolta dello stack di chiamate, ecc.). Alcuni compilatori potrebbero effettivamente essere in grado di ottimizzarlo, ma non lo farei in questo caso, perché le eccezioni non sono pensate per tale uso, quindi non ci si può aspettare che le persone ottimizzino per questo.
  • L'utilizzo delle eccezioni per il controllo del flusso è in realtà un salto, simile a goto . I salti sono considerati dannosi, per una serie di motivi. Dovrebbero essere usati, se tutte le alternative presentano notevoli svantaggi. Infatti, in tutto il mio codice ricordo solo 2 casi, in cui i salti erano chiaramente la soluzione migliore.
risposta data 12.09.2011 - 20:49
fonte
9

A volte le eccezioni sono più veloci. Ho visto casi in cui le eccezioni agli oggetti null erano più veloci anche in Java rispetto all'uso delle strutture di controllo (non posso citare lo studio al momento, quindi dovrai fidarti di me). Il problema arriva quando Java deve effettivamente impiegare il tempo e popolare la traccia dello stack di una classe di eccezioni personalizzata invece di usare quelle native (che sembrano essere almeno parzialmente in cache). Prima di dire che qualcosa è unilateralmente più veloce o più lento, sarebbe un buon punto di riferimento.

In Python non è solo più veloce, ma è molto più corretto fare qualcosa che potrebbe causare un'eccezione e quindi gestire l'errore. Sì, puoi imporre un sistema di tipi, ma ciò va contro la filosofia della lingua - invece dovresti semplicemente provare a chiamare il metodo e prendere il risultato! (Verificare se un file è scrivibile è simile - prova a scriverci e prendi l'errore)

Ho visto volte in cui è più veloce fare qualcosa di stupido come le tabelle di query che non c'erano, piuttosto che capire se esiste una tabella in PHP + MySQL (il domanda in cui punto di riferimento questa è in realtà la mia unica risposta accettata con voti negativi ).

Detto questo, l'uso delle eccezioni dovrebbe essere limitato per diversi motivi:

  1. Ingestione accidentale di eccezioni nidificate Questo è importante. Se trovi qualche eccezione profondamente annidata che qualcun altro sta cercando di gestire, hai appena sparato al tuo compagno programmatore (forse anche tu!) Al piede.
  2. I test diventano non ovvi. Un blocco di codice che ha un'eccezione potrebbe avere una delle molte cose sbagliate. Un booleano, d'altra parte, mentre teoricamente potrebbe essere fastidioso eseguire il debug, generalmente non lo è. Ciò è particolarmente vero in quanto gli aderenti al flusso di controllo try...catch generalmente (nella mia esperienza) non seguono la filosofia "minimizza codice nel blocco di prova".
  3. Non ammette un blocco di else if . Basta dire (e se qualcuno contrasta con un "Ma potrebbero usare diverse classi di eccezioni", la mia risposta è "Vai nella tua stanza e non venire fuori finché non hai pensato a quello che hai detto. ")
  4. È grammaticalmente fuorviante. Exception , al resto del mondo (come non aderisce alla filosofia try...catch control-flow), significa che qualcosa è entrato in un unstable (anche se forse recuperabile) stato. Gli stati instabili sono BAD e dovrebbero tenerci tutti svegli di notte se in realtà abbiamo delle eccezioni evitabili (in realtà mi insinua, non ci sono bugie).
  5. Non è conforme allo stile di codifica comune. Il nostro lavoro, sia con il nostro codice che con la nostra interfaccia utente, è rendere il mondo il più ovvio possibile. try...catch control-flow va contro quelle che sono comunemente considerate best practice. Ciò significa che è necessario più tempo per chi è nuovo di un progetto per apprendere il progetto, il che significa un aumento del numero di ore di lavoro senza alcun guadagno.
  6. Questo spesso porta alla duplicazione del codice. Infine i blocchi, benché ciò non sia strettamente necessario, devono risolvere tutti i puntatori penzolanti che sono stati lasciati aperti dal blocco try interrotto. Quindi prova i blocchi. Ciò significa che puoi avere un try{ obj.openSomething(); /*something which causes exception*/ obj.doStuff(); obj.closeSomething();}catch(Exception e){obj.closeSomething();} . In uno scenario più tradizionale, if...else , closeSomething() è meno probabile (ancora una volta, esperienza personale) essere un lavoro di copia e incolla. (Ammetto che questa particolare discussione ha più a che fare con le persone che ho incontrato rispetto alla filosofia stessa).
risposta data 23.05.2017 - 14:40
fonte
4

Il mio argomento principale è che l'utilizzo di try / catch per la logica interrompe il flusso logico. Seguire la "logica" attraverso costrutti non logici è (per me) contro-intuitivo e confuso. Sono abituato a leggere la mia logica come "if Condition then A else B". Leggere la stessa frase di "Prova a catturare e poi eseguire B" è strano. Sarebbe ancora più strano se l'istruzione A fosse un compito semplice, richiedendo codice extra per forzare un'eccezione se condition è falso (e farlo probabilmente richiederebbe comunque un if -statement).

    
risposta data 12.09.2011 - 20:42
fonte
2

Bene, solo una questione di etichetta, prima di "iniziare una discussione con loro", come lo dichiari, vorrei gentilmente chiedere "Perché usano la gestione delle eccezioni in tutti questi diversi posti?"

Voglio dire, ci sono diverse possibilità:

  1. sono incompetenti
  2. c'è una ragione perfettamente valida per quello che hanno fatto, che potrebbe non apparire a prima vista.
  3. a volte è una questione di gusti e può semplificare un flusso di programma complesso.
  4. È una reliquia del passato che nessuno è ancora cambiato e sarebbero felici se qualcuno lo facesse

... Penso che tutti questi siano ugualmente probabili. Quindi chiedile gentilmente.

    
risposta data 12.09.2011 - 22:05
fonte
1

Prova Catch dovrebbe essere usato solo per la gestione delle eccezioni. Più così, gestione eccezioni specifica. Il tuo tentativo di cattura dovrebbe catturare solo le eccezioni previste, altrimenti non è ben formato. Se hai bisogno di usare una cattura, prova a prendere, quindi probabilmente stai facendo qualcosa di sbagliato.

EDIT:

Motivo: puoi sostenere che se utilizzi try catch come operatore condizionale, come gestirai le eccezioni REAL?

    
risposta data 12.09.2011 - 20:39
fonte
1

Le eccezioni sono per quando accade una cosa Eccezionale. Il programma funziona in modo regolare e regolare?

    
risposta data 12.09.2011 - 20:48
fonte
1

Motivo per utilizzare le eccezioni:

  1. Se ti dimentichi di cogliere una circostanza eccezionale, il tuo programma morirà e la traccia dello stack ti dirà esattamente perché. Se dimentichi di gestire il valore di ritorno per una circostanza di eccezione, non ti viene detto quanto lontano il tuo programma mostrerà un comportamento scorretto.
  2. L'uso dei valori di ritorno funziona solo se è possibile restituire un valore sentinella. Se tutti i possibili valori di ritorno sono già validi, cosa hai intenzione di fare?
  3. Un'eccezione porterà ulteriori informazioni su ciò che è successo e che potrebbe essere utile.

Motivi per non utilizzare le eccezioni:

  1. Molte lingue non sono progettate per rendere veloci le eccezioni.
  2. Le eccezioni che spostano più livelli sullo stack possono lasciare uno stato inconsistente nella loro scia

Alla fine:

L'obiettivo è scrivere un codice che comunichi cosa sta succedendo. Le eccezioni possono aiutare / ostacolare ciò a seconda di cosa sta facendo il codice. Un try / catch in python per un KeyError su un riferimento al dizionario è perfettamente (purché tu conosca la lingua) try / catch per lo stesso KeyError di cinque layer di funzione è pericoloso.

    
risposta data 13.09.2011 - 00:38
fonte
0

Uso try- > come controllo del flusso in certe situazioni. Se la tua logica primaria dipende da qualcosa che fallisce, ma non vuoi semplicemente lanciare un'eccezione e uscire ... È a questo che serve un blocco catch di try- & gt ;. Scrivo molti script unix non controllati sul lato server, ed è molto più importante per loro non fallire, piuttosto che per loro fallire graziosamente.

Quindi prova piano A, e se il piano A muore, cattura ed eseguito con il piano B ... E se il piano B fallisce, usa finalmente per dare il via al Piano C, che risolverà uno dei servizi falliti in A o B, o pagherai.

    
risposta data 12.09.2011 - 23:12
fonte
0

Dipende dalla lingua e forse dall'implementazione utilizzata. Lo standard in C ++ è che le eccezioni dovrebbero essere salvate per eventi veramente eccezionali. D'altra parte, in Python una delle linee guida è " è più facile chiedere perdono che per il permesso ", quindi l'integrazione di try / tranne i blocchi nella logica del programma è incoraggiata.

    
risposta data 13.09.2011 - 01:31
fonte
-1

È una cattiva abitudine, ma lo faccio di volta in volta in python. Come invece di controllare per vedere se esiste un file, cerco semplicemente di eliminarlo. Se lancia un'eccezione, prendo e continuo a sapere che non era lì. < == (non necessariamente vero se un altro utente possiede il file, ma lo faccio nella home directory di un utente, quindi questo NON DEVE accadere).

Ancora, abusato è una cattiva pratica.

    
risposta data 12.09.2011 - 20:50
fonte
-1

Mi piace il modo in cui Apple definisce it: le eccezioni riguardano solo errori del programmatore ed errori irreversibili di runtime. Altrimenti utilizzare i codici di errore. Mi aiuta a decidere quando usarlo, pensando a me stesso "Era un errore del programmatore?"

    
risposta data 12.09.2011 - 21:26
fonte
-1

Sembra usare la gestione delle eccezioni per costruire la logica goto su un linguaggio che non ha un comando goto.

Per i molti motivi per cui la logica goto è cattiva, puoi fare riferimento a questa domanda: link

    
risposta data 23.05.2017 - 14:40
fonte

Leggi altre domande sui tag