2010-10-05 13 views
48

Ci sono 3 permutazioni di un try ... catch ... finally block in java.Hai davvero bisogno del blocco 'finally'

  1. try ... catch
  2. try ... catch ... finally
  3. provare ... finalmente

Una volta che il blocco finally viene eseguito, il controllo passa alla riga successiva dopo il blocco finale. Se rimuovo il blocco finally e spostiamo tutte le sue istruzioni sulla linea dopo il blocco try ... catch, ciò avrebbe lo stesso effetto di averle nel blocco finally?

+3

Questa domanda ha avuto risposta prima di http://stackoverflow.com/questions/3354823/how-to-use-finally. Quindi è un duplicato –

+1

[Il codice in un blocco finally è garantito per l'esecuzione! Sempre! Nessuna eccezione!] (Http://thedailywtf.com/Articles/My-Tales.aspx) – badp

+0

@Shervin, hai letto entrambe le domande prima di contrassegnarlo come duplicato –

risposta

42

Penso che willcode si avvicini di più a esprimere il punto chiave qui, e probabilmente tutti lo intendono ma non sono chiari.

Il problema è che c'è davvero qualcosa di molto sbagliato in quello che stai chiedendo: "Se scrivo tutte le istruzioni dopo il blocco catch invece di scriverle in un blocco finale, allora ci sarebbe qualcosa di sbagliato?"

Se si scrivono tutte le dichiarazioni dopo il blocco catch, ciò che si sta insinuando è che

1) Sarete sempre intercettare l'eccezione.

2) Sarete sempre continuare con la successivi bilanci dopo si cattura l'eccezione.

Ciò implica che vi sarà sempre continuare l'esecuzione "normalmente" dopo un'eccezione, che è generalmente qualcosa che si mai in realtà vogliono fare.

Le eccezioni dovrebbero essere proprio questo: eccezionale. Se in effetti è possibile gestire un'eccezione, è sempre preferibile scrivere il codice per considerare prima tali condizioni e non generare affatto un'eccezione. Se segui questo modello, le eccezioni sono davvero eccezionali, condizioni che non potevi prevedere o al massimo non risolvere. Davvero non è previsto ciò a cui dovresti lavorare. Ciò significa che in generale non è possibile gestire le eccezioni true, il che significa anche che non si deve solo continuare l'esecuzione, spesso si termina l'applicazione.

Ciò che viene normalmente fatto è consentire a un errore di propagare il backup dello stack di chiamate. Alcuni dicono che questo è fatto nella remota possibilità che qualcuno più in alto nella catena possa essere in grado di gestirlo. Direi che essenzialmente non succede mai, ci sono due veri scopi per farlo. Uno può essere qualcosa che l'utente può correggere, se ce n'è uno. Quindi si propagherà l'errore di backup fino a quando non si arriva a dove è possibile segnalarlo all'utente. O due, un utente non può aggiustarlo ma si desidera ottenere l'intero stack di chiamate per il debug. Poi lo prendi in alto per fallire con grazia.

Il blocco finale ora dovrebbe avere più significato per voi. Come dicono tutti, corre sempre. L'uso più chiaro di un finalmente è davvero in un tentativo ... finalmente blocco. Quello che stai dicendo ora è se il codice funziona bene, ottimo. Dobbiamo ancora fare un po 'di pulizia e alla fine eseguiamo sempre, poi procediamo. Ma se si verifica un'eccezione, ora abbiamo davvero bisogno di un blocco definitivo perché potremmo ancora aver bisogno di fare un po 'di pulizia, ma qui non stiamo più rilevando l'eccezione, quindi non avremo più intenzione di andare avanti. Il blocco finale è essenziale per garantire che si verifichi la pulizia.

L'idea di un'eccezione che interrompe sempre l'esecuzione può essere difficile da afferrare fino a quando non hanno una certa esperienza, ma in realtà è il modo di fare sempre le cose. Se si è verificato un errore, o è stato così piccolo che dovresti averlo considerato all'inizio, oppure ci sono sempre più errori in attesa di accadere lungo la linea.

Errori di "deglutizione": catturarli e andare avanti è la cosa peggiore che puoi fare perché il tuo programma diventa imprevedibile e non riesci a trovare e correggere bug.

Il codice ben scritto conterrà altrettanti tentativi ... infine i blocchi necessari per garantire che le risorse vengano sempre rilasciate indipendentemente dal risultato. Ma il codice ben scritto in genere contiene solo un piccolo numero di try ... cattura i blocchi che esistono principalmente per consentire a un'applicazione di fallire nel modo più aggraziato possibile, o rimandare all'utente, il che significa che almeno passa sempre un messaggio all'utente, ecc. Ma di solito non prendi semplicemente un errore e vai avanti.

+2

ho avuto la stessa risposta dal mio manager alcuni minuti fa –

+3

La tua conclusione (1 e 2) è assolutamente sbagliata - No, questa domanda non implica che otterrà sempre eccezioni e/o continuerà sempre con le istruzioni conseguenti. 1) Anche se non si rileva un'eccezione, si continua comunque sulle righe successive a meno che non si ritorni dalla funzione; 2) Se non si ritorna, non importa si procede con try block o catch - si continua SEMPRE con le istruzioni conseguenti (se ce ne sono), e questo è corretto, non c'è niente di sbagliato qui. Avrei risposto, che si può tornare durante il tentativo - ma alla fine verrà comunque eseguito. Questa è la differenza. –

2

Sì, ci sarebbe qualcosa di molto gravemente sbagliato.

E cioè, il codice verrà eseguito solo se c'è un errore.

Le dichiarazioni all'interno di finally vengono sempre eseguite, indipendentemente dall'esecuzione di un'eccezione. Questo è il punto.

+2

Codice di pulizia, ad esempio, che desideri eseguire se non c'è un errore Questo appartiene a un blocco finale. –

+0

Puoi assicurarti che si errori ogni volta aggiungendo Throw new Exception(); come ultima battuta nel blocco Try LOL – JumpingJezza

+2

Penso che tu abbia frainteso "tutte le dichiarazioni dopo il catch block", a me sembra che provi {...; } catturare { ....; } * tutte le dichiarazioni *; – Maxem

38

Un blocco finally è garantito per essere eseguito anche se viene sollevata un'eccezione. Li usi per eseguire la pulizia necessaria come la chiusura dei flussi. Il codice dopo il blocco finally potrebbe non essere mai raggiunto.

Dal java tutorial

blocco finally sempre eseguito quando il blocco uscite provare. Ciò assicura che il blocco finally venga eseguito anche se si verifica un'eccezione imprevista. Tuttavia, è utile per più di una semplice gestione delle eccezioni: consente al programmatore di evitare di avere il codice cancellato accidentalmente da un ritorno , continuare o interrompere. Mettere il codice di pulizia in un blocco finally è sempre una buona pratica, anche quando non sono previste le eccezioni .

+1

@articlestack ricorda anche che il blocco finale non verrà chiamato quando System.exit(); è chiamato. –

+1

@Suresh S: buon punto, ma comunque nel caso di System.exit ... non importa ... (le risorse vengono liberate a livello di sistema operativo) – helios

+0

@helios Non è possibile generalizzare specialmente se il processo sta utilizzando risorse di un altro processo. – reubenjohn

3

Il blocco finally contiene righe di codice che devono essere eseguite indipendentemente dal fatto che sia stata rilevata o meno un'eccezione. Anche se decidi di interrompere il codice in esecuzione con quel metodo. Quindi il codice dopo il t-c-f potrebbe non essere eseguito, ma il codice finale è "garantito" (garantito nel senso di un errore non gestibile che si interrompe immediatamente e che non può essere gestito).

+0

cosa succede se prova ... cattura è lì. Ma sto scrivendo frasi di riposo senza blocco o blocco finale? qual è la differenza? –

1

infine blocco utilizzato in particolare al momento della prevenzione delle eccezioni. Se si verifica un errore di runtime, il programma può portare alla chiusura. Quindi, in questo momento, chiamerà finalmente il blocco prima di andare a chiudere il programma. Di solito 'finally' contiene le istruzioni di chiusura della connessione, le operazioni di salvataggio e l'input del file, le operazioni di chiusura dell'output.

10

Se ho capito la domanda, si sta chiedendo che cosa è la differenza tra:

try { 
    Foo f = new Foo(); 
    f.bar(); 
} 
finally 
{ 
    Foo.baz(); 
} 

E:

// This doesn't actually compile because a try block needs a catch and/or finally block 
try { 
    Foo f = new Foo(); 
    f.bar(); 
} 
Foo.baz(); 

O, più probabilmente:

Foo f = new Foo(); 
f.bar(); 
Foo.baz(); 

la differenza è che se new Foo() o f.bar() generano un'eccezione, loIl bloccoverrà eseguito nel primo caso, ma quello Foo.baz() non verrà eseguito negli ultimi due casi: invece il controllo salterà su Foo.baz() mentre la JVM cerca un gestore di eccezioni.


EDIT

rispondere al tuo commento, che dire:

Foo f = new Foo(); 
try { 
    f.bar(); 
} 
catch (Exception ex) 
{ 
    // ... 
} 

f.baz(); 

Hai ragione che, assumendo il blocco catch non rigenerare l'eccezione, o tornare dal metodo indicando un errore, allora viene chiamato f.baz() indipendentemente dal fatto che ci sia stata un'eccezione. Anche in questo caso, tuttavia, il blocco finally funge da documentazione che viene utilizzato per la pulizia da f.baz(). Ancora più importante, il fatto che di solito sia stata lanciata un'eccezione è importante, quindi è molto difficile scrivere codice che continui a fare qualunque cosa stia facendo senza sapere che è stata lanciata un'eccezione. Ci sono volte in cui le eccezioni indicano cose sciocche che puoi ignorare, e in tal caso dovresti ingoiare l'eccezione. Più spesso, tuttavia, si vorrà segnalare l'errore, rilanciando l'eccezione (o generando un'eccezione diversa) o ritornando dal metodo con un codice di errore.

Per esempio, se si suppone f.bar() per convertire un String ad un Double, e in caso di fallimento si getta un NumberFormatException, poi il codice dopo il blocco try probabilmente ha bisogno di sapere che il String non è stato effettivamente convertito in un Double. E, quindi, in generale non vorrai continuare dopo il blocco catch. Invece, vorrai segnalare un fallimento. Questo è noto come "abort on failure" (rispetto a "resume on failure", che probabilmente dovrebbe essere chiamato "confusione dopo fallimento con le dita incrociate").

Tranne che, in casi particolari, si può essere in grado di cavarsela. Ad esempio, il blocco catch potrebbe impostare il valore Double corrispondente a Double.NaN, progettato specificamente per propagare correttamente gli errori nelle espressioni matematiche. Anche in questo caso, il blocco finally funge da documentazione che f.baz() è coinvolto in una sorta di pulizia.

+1

non verrà compilato né il primo né il secondo frammento di codice. 'f' non è definito in' f.baz() '. (Basta chiamare 'baz()' senza 'f' farebbe) –

+0

Hai ragione. Grazie. Fisso. –

+1

Stavo dicendo che provate e prendete entrambi i blocchi. Ora, qual è il bisogno di finalmente? Perché se è stato rilevato un errore e è stata intrapresa un'azione specifica, deve essere eseguita la successiva istruzione (o finally {} o l'istruzione dopo catch {}). –

1

Se il codice non genera mai eccezioni, o si sta consumando tutte le eccezioni che saranno corrette. Non è quello che succede sempre.

0

Due mesi fa ho scritto un post per the reason behind 'finally' in a try/catch.

Consapevole che un link ottiene nel modo di editing in modo stile wiki qui.

Si tratta di un messaggio autonomo che, semplicemente copiandolo, non funzionerebbe come si perderebbe il commento di follow-up che aggiunge anche valore.

28

So che questa è una domanda molto vecchia ma mi sono imbattuto oggi e sono stato confuso dalle risposte fornite. Voglio dire, sono tutti corretti ma tutti rispondono a un livello teorico o addirittura filosofico quando c'è una risposta pratica molto semplice a questa domanda.

Se si inserisce un ritorno, un'interruzione, una continua o qualsiasi altra parola chiave java che modifica l'esecuzione sequenziale del codice all'interno del blocco catch, le istruzioni all'interno del blocco finally verranno comunque eseguite.

Ad esempio:

public void myFunc() { 

    double p = 1.0D; 
    String str = "bla"; 
    try{ 
     p = Double.valueOf(str); 
    } 
    catch(Exception ex){ 
     System.out.println("Exception Happened"); 
     return; //return statement here!!! 
    }finally{ 
     System.out.println("Finally"); 
    } 
    System.out.println("After finally"); 
} 

quando viene eseguito questo codice stamperà:

Exception Happened 
Finally 

Questa è la ragione più importante per l'esistenza di un blocco finally. La maggior parte delle risposte implica o fa riferimento ad esso in disparte, ma nessuna di esse pone l'accento su di essa. Penso che, trattandosi di una specie di principiante, una risposta così semplice sia molto importante.

+1

+1 completamente d'accordo con te –

Problemi correlati