Cosa mettere in una prova / cattura? [duplicare]

23

Nota sulla domanda: questo non è un duplicato, Prova efficiente / è stato chiesto l'utilizzo del blocco catch dopo questo. L'altra domanda è il duplicato.

Mi chiedevo quale fosse il modo migliore per usare try / catch. È meglio limitare al minimo il contenuto del blocco try o inserire tutto in esso?

Lasciami spiegare con un esempio:

Codice 1:

try {
  thisThrowsAnException();
}
catch (Exception e) {
  e.printStackTrace();
}
thisDoesnt();

Codice 2:

try {
  thisThrowsAnException();
  thisDoesnt();
}
catch (Exception e) {
  e.printStackTrace();
}

Supponendo che thisThrowsAnException() ... beh ... possa generare un'eccezione e thisDoesnt() ... sono sicuro che l'hai ottenuto.

Conosco la differenza tra i due esempi: nel caso in cui venga rilevata l'eccezione, verrà chiamato thisDoesnt() nel primo caso, non nel secondo. Poiché non importa per me, perché il lancio di tale eccezione significherebbe che l'applicazione dovrebbe fermarsi, perché si dovrebbe usare una versione migliore rispetto all'altra?

    
posta SteeveDroz 09.06.2011 - 08:28
fonte

8 risposte

45

Secondo me dovresti mettere tutto nel blocco che dipende dalla parte che genera l'eccezione. Quindi se nel tuo secondo esempio:

try {
  thisThrowsAnException();
  thisDoesnt();
}
catch (Exception e) {
  e.printStackTrace();
}

Se thisDoesnt(); dipende da un'esecuzione corretta di thisThrowsAnException() , dovrebbe essere inclusa.

Ha senso eseguirlo se thisThrowsAnException() fallisce?

    
risposta data 09.06.2011 - 08:32
fonte
16

È importante notare che rilevando un'eccezione si sta assumendo la responsabilità di recuperare da esso. L'ambito del blocco try deve dipendere dal modo in cui tale ripristino deve essere eseguito. Ad esempio, guarda questi due frammenti di codice:

Snippet 1:

for (Object object : objects) {
    try {
        performTaskOnObject(object);
    } catch (Exception e) {
        log.error("Failed to perform task on object", e);
    }
}

Snippet 2:

try {
    for (Object object : objects) {
        performTaskOnObject(object);
    }
} catch (Exception e) {
    log.error("Failed to perform task on objects", e);
}

Semplicemente modificando l'ambito del blocco try , questi due frammenti presentano due strategie di recupero molto diverse. Snippet 1 consente di tentare l'attività per il resto Object s anche dopo uno o più errori. Snippet 2 non consente di tentare l'attività per il restante Object s dopo un errore.

La tua strategia di recupero dovrebbe essere la guida per il controllo del limite di try .

    
risposta data 09.06.2011 - 11:22
fonte
11

Come Michael ha già detto , non è solo una questione di stile di codifica o di buone pratiche, devi mantenere l'algoritmo in mente.

Il vantaggio del codice 1 è maintainablity . Il try / catch racchiude solo quella riga di codice che può generare l'eccezione. Quindi, se vediamo un blocco try / catch, è immediatamente chiaro, l'operazione che può lanciarla. Questo è abbastanza utile se abbiamo una serie di operazioni che generano varie eccezioni IO. E se rimuoviamo una dichiarazione o rifattiamo parte del codice in un metodo separato, allora non perdiamo i gestori delle eccezioni o lasciamo gestori di try / catch non necessari (di eccezioni di runtime rilevate).

Il vantaggio del codice 2 è readabilty . Per molti try / catch i blocchi ingombrano davvero un metodo e diventa estremamente difficile vedere il vero algoritmo dietro a tutte quelle istruzioni try / catch e ai gestori.

Nel mio codice preferisco la versione 2, la versione che ha una maggiore possibilità di portare a codice pulito. Anche se, devo prestare maggiore attenzione durante il refactoring.

Trivia - ciò che non dovresti inserire in un blocco catch è una dichiarazione e.printStackTrace(); ;) Ti consiglio davvero di aggiungere log4j (o qualcosa di simile) e modifica i modelli IDE per inizializzare il blocco catch con log.debug(e)

    
risposta data 09.06.2011 - 09:07
fonte
1

Preferirei la prima versione, quindi diventa chiaro per il lettore umano quale parte del programma lancia l'eccezione e come viene gestita. In un programma del mondo reale, thisDoesnt() sarebbe costituito da diverse righe di codice e, per pura fortuna, uno di essi potrebbe generare eccezioni, ma la versione 2 del codice nasconderà questo fatto, quindi la gestione delle eccezioni potrebbe fare la cosa sbagliata perché è pensato per gestire un errore di thisThrowsAnException(); . E quelle diverse righe di thisDoesnt() separano il gestore di eccezioni da thisThrowsAnException(); , rendendo più difficile vedere la connessione.

Pertanto, la mia versione del codice sarebbe simile a quella

boolean success=false;
try {
  thisThrowsAnException();
  success=true;
}
catch (Exception e) {
  e.printStackTrace();
}

if (success) {
  thisDoesnt();
}

o con un'uscita anticipata in caso di errore:

try {
  thisThrowsAnException();
}
catch (Exception e) {
  e.printStackTrace();
  return null;  // false, "", whatever; or rethrow the exception
}

thisDoesnt();
    
risposta data 09.06.2011 - 10:24
fonte
0

Nota: due modi per implementare "l'applicazione dovrebbe fermarsi".

  1. Lanciare un'eccezione e lasciare che bolla fino a un gestore di errori centrale che fa ciò che devi fare e poi esce dal programma (o riprova o qualsiasi altra cosa).

  2. Chiamando "System.exit (1)". Questo è raramente quello che vuoi, tranne nei programmi più semplici, e ancora più raro, ad es. un'applicazione web in cui un semplice errore potrebbe causare l'arresto anomalo del server Web. Inoltre, le risorse non vengono rilasciate correttamente, ecc.

Raccomando vivamente di imparare come usare le eccezioni per indicare e recuperare dagli errori invece di usare System.exit (). Anche la clausola finally è molto importante per la pulizia delle risorse.

Nella tua domanda, se thisDoesnt() deve essere eseguito indipendentemente dal fatto che thisThrowsAnException() fallisca o meno, allora è il codice 1. Se deve essere eseguito solo se non fallisce, allora il codice 2.

    
risposta data 09.06.2011 - 08:57
fonte
0

I due codici stanno facendo cose diverse in presenza di eccezioni. Non c'è preferenza con l'una o l'altra, usa quella che fa ciò che è necessario.

    
risposta data 09.06.2011 - 11:34
fonte
-1

Sarà una decisione di gioco per ognuno. Se hai un codice che può generare eccezioni che non sono assolutamente necessarie per il programma, allora mettilo da solo nel blocco try. In questo modo, nel blocco delle catture, puoi occuparti di dove andare dopo.

Un buon modello di progettazione per questo è di avere un metodo di supporto che può determinare se un errore è fatale (terminare la sessione, chiudere il programma, qualunque cosa) o meno, e quindi ripensare o meno in base al risultato di tale verifica. Qualcosa come:

try{
    foo();
}
catch(Exception ex)
{
    bool rethrow = ExceptionHelper.Handle(ex);  //should return true if error is fatal, false if not
    if(rethrow) throw;
}
    
risposta data 04.05.2012 - 17:45
fonte
-1

Secondo me, ci possono essere due condizioni, una che vogliamo eseguire il programma prima che si verifichi un'eccezione e la prossima non lo facciamo. L'ultimo è semplice, è sufficiente accedere all'errow o dare una definizione adeguata all'eccezione verificatasi e scappare.

Nel primo caso:

Semplifica la comprensione

Stiamo scrivendo un programma per aggiungere liste o numeri come (a1 / x) + (a1 / x) + (a3 / x) + ...

come questo:

try {
  sum=(a1/x)+(a1/x)+(a3/x)+...;
}
catch (Exception e) {
  e.printStackTrace();
}
syso.(sum);

Ora se qualcuno ha inserito x = 0, si verifica un'eccezione. Ora vuoi che il programma finisca in questo modo?

vorremmo scrivere in questo modo

try {
  sum=(a1/x)+(a1/x)+(a3/x)+...;
  syso.(sum);
}
catch (Exception e) {
  e.printStackTrace();//optional
  syso("Hey man! You cannot divideanything by zero!!! Its infinity");//something like this
}

o per essere più chiari:

try {
  sum=(a1/x)+(a1/x)+(a3/x)+...;
}
catch (Exception e) {
    syso("Hey man! You cannot divideanything by zero!!! Its infinity");//something like this
    sum=(a1/y)+(a1/y)+(a3/y)+...;
}
syso(sum);

Nota dove syso(sum) è posizionato

Spero che ti dia un'idea un po 'chiara :)

    
risposta data 10.06.2011 - 09:14
fonte

Leggi altre domande sui tag