Considerando questo codice, posso essere assolutamente sicuro che il blocco finally
venga eseguito sempre, non importa quale something()
sia?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
Sì, finally
verrà chiamato dopo l'esecuzione dei blocchi di codice try
o catch
.
Le uniche volte in cui finally
non verrà chiamato sono:
System.exit()
try
o catch
kill -9 <pid>
su UNIXfinally
verrà eseguito da un thread daemon e tutti gli altri thread non daemon escono prima che venga chiamato finally
Codice di esempio:
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int test() {
try {
return 0;
}
finally {
System.out.println("finally trumps return.");
}
}
Produzione:
finally trumps return.
0
Inoltre, anche se è una cattiva pratica, se c'è un'istruzione return nel blocco finally, trionferà qualsiasi altro ritorno dal blocco regolare. Cioè, il seguente blocco restituirebbe falso:
try { return true; } finally { return false; }
Stessa cosa con il lancio di eccezioni dal blocco finale.
Ecco le parole ufficiali della specifica del linguaggio Java.
14.20.2. Esecuzione di try-finally e try-catch-finally
Un'istruzione
try
con un bloccofinally
viene eseguita eseguendo prima il bloccotry
name__. Quindi c'è una scelta:
- Se l'esecuzione del blocco
try
termina normalmente, [...]- Se l'esecuzione del blocco
try
termina bruscamente a causa di unthrow
di un valore V, [...]- Se l'esecuzione del blocco
try
termina bruscamente per qualsiasi altra ragione R, viene eseguito il bloccofinally
name__. Poi c'è una scelta:
- Se il blocco finally viene completato normalmente, l'istruzione
try
viene completata improvvisamente per la ragione R.- Se il blocco
finally
termina bruscamente per la ragione S, allora l'istruzionetry
termina bruscamente per la ragione S ( e la ragione R viene scartata ).
La specifica per return
rende esplicitamente questo:
JLS 14.17 Dichiarazione di reso
ReturnStatement: return Expression(opt) ;
Un'istruzione
return
con nessun tentativoExpression
per trasferire il controllo al invoker del metodo o costruttore che lo contiene.Un'istruzione
return
con unExpression
tentativi per trasferire il controllo al invoker del metodo che lo contiene; il valore diExpression
diventa il valore dell'invocazione del metodo.Le descrizioni precedenti dicono " tentativi per trasferire il controllo " piuttosto che solo " trasferimenti controllo " perché se esistono istruzioni
try
all'interno del metodo o del costruttore i cui blocchitry
contengono l'istruzionereturn
name__, allora tutte le clausolefinally
di quelle istruzionitry
verranno eseguite, nell'ordine, più esterne a quelle più esterne, prima che il controllo venga trasferito all'invoker del metodo o costruttore . Il completamento brusco di una clausolafinally
può interrompere il trasferimento del controllo avviato da un'istruzionereturn
name__.
Oltre alle altre risposte, è importante sottolineare che "finally" ha il diritto di ignorare qualsiasi eccezione/valore restituito dal blocco try..catch. Ad esempio, il seguente codice restituisce 12:
public static int getMonthsInYear() {
try {
return 10;
}
finally {
return 12;
}
}
Allo stesso modo, il seguente metodo non genera un'eccezione:
public static int getMonthsInYear() {
try {
throw new RuntimeException();
}
finally {
return 12;
}
}
Mentre il seguente metodo lo lancia:
public static int getMonthsInYear() {
try {
return 12;
}
finally {
throw new RuntimeException();
}
}
Ho provato l'esempio sopra con leggera modifica-
public static void main(final String[] args) {
System.out.println(test());
}
public static int test() {
int i = 0;
try {
i = 2;
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
}
}
Il codice sopra riportato produce:
finalmente briscola ritorno.
2
Questo perché quando return i;
viene eseguito i
ha un valore 2. Successivamente viene eseguito il blocco finally
in cui 12 è assegnato a i
e quindi System.out
out viene eseguito.
Dopo aver eseguito il blocco finally
il blocco try
restituisce 2, anziché restituire 12, perché questa dichiarazione di ritorno non viene eseguita nuovamente.
Se esegui il debug di questo codice in Eclipse, avrai la sensazione che dopo l'esecuzione di System.out
di finally
block l'istruzione return
del blocco try
venga eseguita nuovamente. Ma questo non è il caso. Restituisce semplicemente il valore 2.
Ecco un'elaborazione di risposta di Kevin . È importante sapere che l'espressione da restituire viene valutata prima di finally
, anche se viene restituita dopo.
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int printX() {
System.out.println("X");
return 0;
}
public static int test() {
try {
return printX();
}
finally {
System.out.println("finally trumps return... sort of");
}
}
Produzione:
X
finally trumps return... sort of
0
Questa è l'idea di un blocco finale. Ti consente di assicurarti di eseguire delle pulizie che altrimenti potrebbero essere saltate perché tu ritorni, tra le altre cose, ovviamente.
Infine viene chiamato indipendentemente da ciò che accade nel blocco try ( a meno che tu chiami System.exit(int)
o Java Virtual La macchina prende il via per qualche altra ragione).
Un modo logico per pensarci è:
alla fine viene sempre eseguito a meno che non ci sia una terminazione anomala del programma (come chiamare System.exit (0) ..). così, il tuo sysout verrà stampato
Anche un ritorno alla fine eliminerà ogni eccezione. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
Il blocco finally viene sempre eseguito a meno che non vi sia una terminazione anomala del programma, risultante da un arresto anomalo di JVM o da una chiamata a System.exit(0)
.
Inoltre, qualsiasi valore restituito dall'interno del blocco finally sovrascriverà il valore restituito prima dell'esecuzione del blocco finally, quindi fai attenzione a controllare tutti i punti di uscita quando usi try finally.
No, non sempre un caso di eccezione è // System.exit (0); prima che il blocco finalmente impedisca di essere finalmente eseguito.
class A {
public static void main(String args[]){
DataInputStream cin = new DataInputStream(System.in);
try{
int i=Integer.parseInt(cin.readLine());
}catch(ArithmeticException e){
}catch(Exception e){
System.exit(0);//Program terminates before executing finally block
}finally{
System.out.println("Won't be executed");
System.out.println("No error");
}
}
}
Finalmente è sempre eseguito questo è il punto, solo perché appare nel codice dopo il ritorno non significa che è così che viene implementato. Il runtime Java ha la responsabilità di eseguire questo codice quando si esce dal blocco try
.
Ad esempio se si ha il seguente:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
Il runtime genererà qualcosa come questo:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
Se viene generata un'eccezione non rilevata, verrà eseguito il blocco finally
e l'eccezione continuerà a propagarsi.
Questo perché il valore di i è stato assegnato a 12, ma non ha restituito il valore di i alla funzione. Il codice corretto è il seguente:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
Perché un blocco finally verrà sempre chiamato a meno che non si chiami System.exit()
(o il thread si blocchi).
La risposta è semplice YES.
INPUT:
try{
int divideByZeroException = 5 / 0;
} catch (Exception e){
System.out.println("catch");
return; // also tried with break; in switch-case, got same output
} finally {
System.out.println("finally");
}
USCITA:
catch
finally
Sì, verrà chiamato. Questo è il punto di avere una parola chiave finalmente. Se saltare fuori dal blocco try/catch potrebbe semplicemente saltare il blocco finally era come mettere System.out.println al di fuori del try/catch.
Sì, finalmente il blocco è sempre eseguito. La maggior parte degli sviluppatori usa questo blocco chiudendo la connessione al database, l'oggetto resultset, l'oggetto statement e anche gli usi nell'ibernazione Java per il rollback della transazione.
Concisamente, nella documentazione ufficiale di Java (Click qui ), è scritto che -
Se la JVM termina mentre viene eseguito il codice try o catch, allora il blocco finally potrebbe non essere eseguito. Allo stesso modo, se il thread che esegue il codice try o catch viene interrotto o ucciso, il blocco finally potrebbe non essere eseguito anche se l'applicazione continua nel suo complesso.
Si lo farà. Solo in questo caso, JVM non si chiude o si blocca
Si lo farà. Non importa cosa succede nel tuo try o catch block a meno che System.exit () non chiami o JVM si arresti. se c'è qualche dichiarazione di ritorno nel blocco (s), infine sarà eseguito prima di tale dichiarazione di ritorno.
Considera il seguente programma:
public class SomeTest {
private static StringBuilder sb = new StringBuilder();
public static void main(String args[]) {
System.out.println(someString());
System.out.println("---AGAIN---");
System.out.println(someString());
System.out.println("---PRINT THE RESULT---");
System.out.println(sb.toString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
A partire da Java 1.8.162, il precedente blocco di codice fornisce il seguente output:
-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz
questo significa che usare finally
per liberare oggetti è una buona pratica come il seguente codice:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null; // Just an example, but you can close streams or DB connections this way.
}
}
Ho provato questo, è single threaded.
class Test {
public static void main(String args[]) throws Exception {
Object obj = new Object();
try {
synchronized (obj) {
obj.wait();
System.out.println("after wait()");
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
Il thread principale sarà in attesa per sempre, quindi, alla fine, non sarà mai chiamato,
quindi l'output della console non stamperà la stringa: after wait()
o finally
Concordato con @Stephen C, l'esempio sopra è uno dei 3 casi qui :
Aggiungendo alcune più possibilità di loop infinito nel seguente codice:
// import Java.util.concurrent.Semaphore;
class Test {
public static void main(String[] args) {
try {
// Thread.sleep(Long.MAX_VALUE);
// Thread.currentThread().join();
// new Semaphore(0).acquire();
// while (true){}
System.out.println("after sleep join semaphore exit infinite while loop");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
Caso 2: se la JVM si arresta prima
import Sun.misc.Unsafe;
import Java.lang.reflect.Field;
class Test {
public static void main(String args[]) {
try {
unsafeMethod();
// Runtime.getRuntime().halt(123);
System.out.println("After Jvm Crash!");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);
}
}
Caso 6: Se finalmente il blocco verrà eseguito dal thread daemon e tutti gli altri thread non daemon escono prima che venga finalmente chiamato.
class Test {
public static void main(String args[]) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
printThreads("Daemon Thread printing");
// just to ensure this thread will live longer than main thread
Thread.sleep(10000);
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
};
Thread daemonThread = new Thread(runnable);
daemonThread.setDaemon(Boolean.TRUE);
daemonThread.setName("My Daemon Thread");
daemonThread.start();
printThreads("main Thread Printing");
}
private static synchronized void printThreads(String str) {
System.out.println(str);
int threadCount = 0;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
System.out.println("Thread :" + t + ":" + "state:" + t.getState());
++threadCount;
}
}
System.out.println("Thread count started by Main thread:" + threadCount);
System.out.println("-------------------------------------------------");
}
}
output: questo non stampa "finally" che implica "finally block" in "daemon thread" non eseguito
main Thread Printing Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED Thread :Thread[main,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:3 ------------------------------------------------- Daemon Thread printing Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:2 ------------------------------------------------- Process finished with exit code 0
Sì, perché nessuna istruzione di controllo può impedire l'esecuzione di finally
.
Ecco un esempio di riferimento, in cui verranno eseguiti tutti i blocchi di codice:
| x | Current result | Code
|---|----------------|------ - - -
| | |
| | | public static int finallyTest() {
| 3 | | int x = 3;
| | | try {
| | | try {
| 4 | | x++;
| 4 | return 4 | return x;
| | | } finally {
| 3 | | x--;
| 3 | throw | throw new RuntimeException("Ahh!");
| | | }
| | | } catch (RuntimeException e) {
| 4 | return 4 | return ++x;
| | | } finally {
| 3 | | x--;
| | | }
| | | }
| | |
|---|----------------|------ - - -
| | Result: 4 |
Nella variante seguente, return x;
verrà saltato. Il risultato è ancora 4
:
public static int finallyTest() {
int x = 3;
try {
try {
x++;
if (true) throw new RuntimeException("Ahh!");
return x; // skipped
} finally {
x--;
}
} catch (RuntimeException e) {
return ++x;
} finally {
x--;
}
}
I riferimenti, ovviamente, tengono traccia del loro stato. Questo esempio restituisce un riferimento con value = 4
:
static class IntRef { public int value; }
public static IntRef finallyTest() {
IntRef x = new IntRef();
x.value = 3;
try {
return x;
} finally {
x.value++; // will be tracked even after return
}
}
finally
verrà eseguito e questo è sicuro.
finally
non verrà eseguito nei seguenti casi:
caso 1 :
Quando stai eseguendo System.exit()
.
caso 2:
Quando il tuo JVM/Thread si blocca.
caso 3:
Quando l'esecuzione viene interrotta tra manualmente.
try
- catch
- finally
sono le parole chiave per l'utilizzo del caso di gestione delle eccezioni.
Come normale esplicativo
try {
//code statements
//exception thrown here
//lines not reached if exception thrown
} catch (Exception e) {
//lines reached only when exception is thrown
} finally {
// always executed when the try block is exited
//independent of an exception thrown or not
}
Il blocco finally impedisce l'esecuzione ...
System.exit(0);
Se non si gestisce l'eccezione, prima di terminare il programma, JVM esegue infine il blocco. Non verrà eseguito solo se la normale esecuzione del programma non riuscirà a significare la conclusione del programma a causa di questi seguenti motivi ..
Provocando un errore fatale che causa l'interruzione del processo.
Cessazione del programma a causa della memoria corrotta.
Chiamando System.exit ()
Se il programma va in loop infinito.
Questo è vero in qualsiasi lingua ... alla fine verrà sempre eseguito prima di una dichiarazione di ritorno, indipendentemente da dove si trovi quel ritorno nel corpo del metodo. Se così non fosse, il blocco finale non avrebbe molto significato.
Aggiungendo a la risposta di @ vibhash poiché nessuna altra risposta spiega cosa succede nel caso di un oggetto mutabile come quello qui sotto.
public static void main(String[] args) {
System.out.println(test().toString());
}
public static StringBuffer test() {
StringBuffer s = new StringBuffer();
try {
s.append("sb");
return s;
} finally {
s.append("updated ");
}
}
Uscirà
sbupdated
Sì, è scritto qui
Se la JVM termina mentre viene eseguito il codice try o catch, allora il blocco finally potrebbe non essere eseguito. Allo stesso modo, se il thread che esegue il codice try o catch viene interrotto o ucciso, il blocco finally potrebbe non essere eseguito anche se l'applicazione continua nel suo complesso.
Oltre al punto sul ritorno in definitiva, in sostituzione di un ritorno nel blocco try, lo stesso vale per un'eccezione. Un blocco finally che genera un'eccezione sostituirà un ritorno o un'eccezione generata all'interno del blocco try.
La specifica del linguaggio Java descrive come funzionano i blocchi try-catch-finally e try-catch in 14.20.2
In nessun punto specifica che il blocco finally viene sempre eseguito. Ma per tutti i casi in cui i blocchi try-catch-finally e try-finally completi, specifica che prima del completamento deve essere infine eseguito.
try {
CODE inside the try block
}
finally {
FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).
Il JLS non garantisce che FIN venga eseguito dopo CODICE. Il JLS garantisce che if CODICE e NEXT siano eseguiti allora FIN verrà sempre eseguito dopo CODICE e prima SUCCESSIVO.
Perché il JLS non garantisce che il blocco finally venga sempre eseguito dopo il blocco try? Perché è impossibile. È improbabile, ma possibile, che la JVM venga interrotta (kill, crash, power off) subito dopo aver completato il blocco try ma prima dell'esecuzione del blocco finally. Non c'è nulla che il JLS possa fare per evitarlo.
Quindi, qualsiasi software che per il loro comportamento corretto dipende da blocchi finalmente eseguiti dopo che i loro blocchi di prova sono stati completati.
I ritorni nel blocco try sono irrilevanti a questo problema. Se l'esecuzione raggiunge il codice dopo il try-catch-finally, è garantito che il blocco finally sarà stato eseguito prima, con o senza resi all'interno del blocco try.
Il blocco finally non verrà chiamato dopo il ritorno in un paio di scenari unici: se System.exit () viene chiamato per primo, o se la JVM si arresta in modo anomalo.
Lasciatemi provare a rispondere alla tua domanda nel modo più semplice possibile.
Regola 1: Il blocco finally viene sempre eseguito (anche se ci sono delle eccezioni ad esso. Ma restiamo fedeli a questo per un po 'di tempo).
Regola 2: le istruzioni nel blocco finally vengono eseguite quando il controllo lascia una prova o un blocco catch.Il trasferimento del controllo può avvenire come risultato della normale esecuzione , di esecuzione di un'interruzione, continua, goto o una dichiarazione di ritorno, o di una propagazione di un'eccezione.
In caso di una dichiarazione di ritorno specifica (dal suo sottotitolo), il controllo deve lasciare il metodo di chiamata, e quindi chiama il blocco finale della corrispondente struttura try-finally. L'istruzione return viene eseguita dopo il blocco finally.
Nel caso in cui sia presente anche una dichiarazione di ritorno nel blocco finally, esso annulla definitivamente quella in sospeso nel blocco try, dal momento che cancella lo stack delle chiamate.
È possibile fare riferimento a una spiegazione migliore qui: http://msdn.Microsoft.com/en-us/ .... il concetto è principalmente lo stesso in tutti i linguaggi di alto livello.
Lo stesso con il seguente codice:
static int f() {
while (true) {
try {
return 1;
} finally {
break;
}
}
return 2;
}
f restituirà 2!
Perché la finale è sempre chiamata in qualunque caso tu abbia. Non hai eccezioni, è ancora chiamato, cattura l'eccezione, è ancora chiamato
Sì, verrà sempre chiamato ma in una situazione non chiamerà quando usi System.exit ()
try{
//risky code
}catch(Exception e){
//exception handling code
}
finally(){
//It always execute but before this block if there is any statement like System.exit(0); then this block not execute.
}
Infine, il blocco esegue sempre se l'eccezione gestisce o meno. Se qualsiasi eccezione si è verificata prima del blocco try, il blocco finally non verrà eseguito.
Se viene lanciata un'eccezione, alla fine viene eseguito. Se non viene lanciata un'eccezione, alla fine viene eseguito. Se viene rilevata l'eccezione, viene infine eseguito. Se l'eccezione non viene rilevata, viene infine eseguita.
Solo il tempo in cui non viene eseguito è quando si esce da JVM.
Considera questo in una normale esecuzione (vale a dire senza alcuna eccezione lanciata): se il metodo non è "vuoto" restituisce sempre qualcosa in modo esplicito, ma alla fine viene sempre eseguito
Prova questo codice, capirai che il codice nel blocco finally viene eseguito dopo l'istruzione return .
public class TestTryCatchFinally {
static int x = 0;
public static void main(String[] args){
System.out.println(f1() );
System.out.println(f2() );
}
public static int f1(){
try{
x = 1;
return x;
}finally{
x = 2;
}
}
public static int f2(){
return x;
}
}
Ero molto confuso con tutte le risposte fornite su diversi forum e ho deciso di finalmente scrivere e vedere. L'uscita è:
infine verrà eseguito anche se c'è un ritorno nel blocco try and catch.
try {
System.out.println("try");
return;
//int i =5/0;
//System.exit(0 ) ;
} catch (Exception e) {
System.out.println("catch");
return;
//int i =5/0;
//System.exit(0 ) ;
} finally {
System.out.println("Print me FINALLY");
}
Uscita
provare
Stampa me FINALMENTE
System.exit(0)
in try e catch block nel codice precedente e si verifica un'eccezione prima di esso, per qualsiasi motivo.infine può anche essere chiuso prematuramente se viene generata un'eccezione all'interno di un blocco finale annidato. Il compilatore ti avvertirà che il blocco finally non si completa normalmente o ti dà un errore se hai un codice irraggiungibile. L'errore per il codice irraggiungibile verrà mostrato solo se il lancio non è dietro un'istruzione condizionale o all'interno di un ciclo.
try{
}finally{
try{
}finally{
//if(someCondition) --> no error because of unreachable code
throw new RunTimeException();
}
int a = 5;//unreachable code
}
Alla fine viene sempre chiamato alla fine
quando provi, esegue del codice, se succede qualcosa in try, quindi catch rileverà quell'eccezione e potresti stampare un mssg out o lanciare un errore, quindi il blocco finally viene eseguito.
Infine viene normalmente utilizzato quando si eseguono le pulizie, ad esempio, se si utilizza uno scanner in Java, è probabile che si debba chiudere lo scanner in quanto porta ad altri problemi come non riuscire ad aprire alcuni file
infine il blocco viene eseguito sempre anche se si inserisce una dichiarazione di ritorno nel blocco try. Il blocco finally verrà eseguito prima dell'istruzione return.