Un tentativo / cattura per ogni errore o un tentativo di intercettazione globale e commuta errore?

3

Ho diversi metodi che potrebbero fallire, diciamo:

  1. readFile ()
  2. ParseFile ()
  3. compute ()

Ciascuno di essi potrebbe fallire (ad es. file non trovato, tipo di file errato, dati errati), dovrei inserire ognuno di loro nel proprio blocco try/catch o dovrei creare un blocco try/catch quindi switch l'errore e registra / visualizza il testo a seconda dell'errore?

per esempio:

try {
    readfile()
}
catch (err) {
    log.error(err);
    throw 'Could not read file';
}

try {
    parsefile()
}
catch (err) {
    log.error(err);
    throw 'File corrupted or wrong type';
}

try {
    compute()
}
catch (err) {
    log.error(err);
    throw 'Data is wrong';
}

o:

try {
    readfile()
    parsefile()
    compute()
}
catch (err) {
    switch(err) {
        case 'NOENT': throw...
        case 'CORRUPTED': throw...
    }
}
    
posta toto 23.11.2018 - 16:55
fonte

3 risposte

6

Sono convinto che il miglior motivo per catturare un'eccezione sia la possibilità di accedere e quindi recuperare in modo da continuare a eseguire il programma , ad esempio, informando l'utente dell'errore in modo che possa svolgere un'azione alternativa.

Ciò di cui stai discutendo qui sono costrutti / schemi alternativi per catturare tutti i rimbalzi.

Questo implica che devi necessariamente avere un'altra prova / cattura più in alto nella catena di chiamate che sta facendo questo recupero.

Questo più alto nel call-stack try / catch può fare il logging, il che rende il try / catch locale (vicino al punto di lancio, dove non è possibile adottare azioni correttive) mi sembra ridondante, e cercherò di eliminare questi costrutti apparentemente inutili.

try {
    parsefile()
}
catch (err) {
    log.error(err);
    throw 'File corrupted or wrong type';
}

Ad esempio, il try / catch sopra potrebbe essere rimosso da (1) affidandosi al try / catch esterno per registrare l'errore e recuperare il programma, e (2) lanciare l'eccezione appropriata in parsefile() in primo luogo .

(Potrebbe anche succedere che il parsefile() stia già generando un'eccezione più utile e specifica che viene poi oscurata rilanciando un'eccezione più generale diversa. Ricordiamo che le eccezioni nella maggior parte delle lingue possono partecipare gerarchia per semplificare alcuni problemi qui.)

(Certo, ci sono momenti in cui questo non è pratico, ma la domanda è posta piuttosto genericamente, quindi questa è una risposta generale)

    
risposta data 23.11.2018 - 18:58
fonte
4

Nella maggior parte delle situazioni, direi "nessuno". Invece, dovresti probabilmente andare con un try seguito da più% parti% co_de.

try {
    readFile();
    parseFile();
    compute();
} catch (ReadFileException err) {
    log.error(err);
    throw new SomeException("Cannot read file", err);
} catch (ParseFileException err) {
    log.error(err);
    throw new SomeException("Cannot parse file", err);
} catch (ComputeException err) {
    log.error(err);
    throw new SomeException("Cannot compute results of file", err);
}

Ciò mantiene unito il codice "flusso felice", semplificando la gestione di casi diversi. La tua seconda opzione ha gli stessi vantaggi, ma sembra corrispondere a qualche messaggio di errore, che è piuttosto fragile. L'utilizzo di diversi tipi di eccezioni offre all'IDE l'opzione per aiutarti.

Una nota: se in realtà c'è un sacco di cose tra catch , readFile() e parseFile() , preferirei invece con blocchi 3 compute() - che cosa significa "un sacco di cose" in questo il caso è una questione di gusto personale, penso, e qualcosa di cui hai bisogno per avere un'idea.

    
risposta data 23.11.2018 - 17:09
fonte
2

Sono pienamente d'accordo con il punto di vista di Erik e vorrei aggiungere un altro ragionamento per sostenere la nostra raccomandazione:

    readFile();
    parseFile();
    compute();

senza alcun try / catch.

Che cos'è un'eccezione?

  • Segnala al chiamante che il tuo metodo non ha avuto successo (adempiere il suo contratto) per qualsiasi motivo.
  • Contiene una descrizione di tale errore, in genere utilizzando una specifica classe di eccezioni, contenente un messaggio e salvando la traccia dello stack in cui si è verificata l'eccezione.
  • Interrompe bruscamente il flusso di controllo corrente nelle esecuzioni del metodo corrente e di tutti i genitori, fino a un punto in cui hai inserito un try / catch corrispondente.

Questo concetto di eccezione è stato progettato in modo ponderato per darti una gestione degli errori ben funzionante quasi gratis.

Nel codice di esempio, vuoi catturare le eccezioni e rilanciarne di differenti. Perché? Cosa pensi che il tuo chiamante farà in base all'eccezione? E in che modo le tue eccezioni tradotte renderanno più facile quel lavoro?

Devo deluderti: in genere il tuo interlocutore non è interessato a tutti in ragione del fallimento. Se il tuo interlocutore ottiene un'eccezione, abortirà semplicemente te stesso e comunicherà al suo interlocutore quel fatto (in genere lasciandoti sfuggire l'eccezione non catturata). Quindi, sostituire l'eccezione con un'altra è una perdita di tempo nel 99% dei casi. Ho raramente visto il codice in cui un metodo ha preso rami diversi a seconda del tipo di eccezione che ha ottenuto.

Da qualche parte nello stack delle chiamate, c'è un posto dove alcuni sviluppatori hanno deciso di provare, perché pensa di poter continuare qui. Ma di solito non si preoccupa del tipo di eccezione. Forse, riproverà la chiamata, o semplicemente mostrerà un messaggio all'utente e attenderà la sua prossima azione. E tutto questo funziona con qualsiasi tipo di eccezione, quindi non c'è ancora alcun motivo per tradurre le eccezioni.

Una cosa di cui ti dovresti preoccupare è la registrazione. Assicurati di registrare ogni eccezione una volta, e solo una volta. Gli amministratori di sistema che eseguono il tuo software ti odieranno se ingombrano i file di log con ripetizioni infinite dello stesso problema, specialmente se lo riscrivi a ogni livello di catch / re-throw. Quindi, non accedere nei luoghi in cui si effettua nuovamente l'eccezione. La registrazione degli errori appartiene ai luoghi in cui le eccezioni vengono rilevate per sempre.

Assicurati che ogni eccezione porti un messaggio utile. Normalmente tutte le eccezioni provenienti da librerie mature avranno in genere un messaggio utile, ma potrebbero esserci casi in cui si desidera aggiungere informazioni (ad esempio sul contesto come un ID oggetto), e questo è un motivo valido per un catch / re-throw. Non accedere qui, ma creare e lanciare una nuova eccezione contenente le informazioni aggiuntive e fare riferimento all'eccezione originale, se la lingua lo supporta (ad esempio Java). Quindi il log eintry ha tutte le informazioni sulle eccezioni originali, in genere inclusa la traccia dello stack, essendo l'aiuto di debug più importante disponibile in un'impostazione di produzione.

Per riassumere con la regola d'oro di gestione delle eccezioni:

  • Non dovresti prendere un'eccezione qui.
  • Davvero non dovresti trovare un'eccezione qui.
  • Se nonostante la regola tieni un'eccezione qui, assicurati di sapere una buona ragione, perché!
risposta data 23.11.2018 - 20:24
fonte

Leggi altre domande sui tag