Does a finally block always get executed in Java?
考虑到这段代码,我可以肯定,无论
1 2 3 4 5 6 7 8 9 10 |
是的,执行
唯一不被调用的时间是:
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 |
输出:
1 2 | finally trumps return. 0 |
另外,尽管这是一个糟糕的实践,但是如果finally块中有一个返回语句,它将胜过常规块中的任何其他返回。也就是说,下面的块将返回false:
1 | try { return true; } finally { return false; } |
与从finally块抛出异常相同。
下面是Java语言规范的官方词汇。
2.20.2.Try Finally和Try Catch Finally的执行
A
try statement with afinally block is executed by first executing thetry block. Then there is a choice:
- If execution of the
try block completes normally, [...]- If execution of the
try block completes abruptly because of athrow of a value V, [...]- If execution of the
try block completes abruptly for any other reason R, then thefinally block is executed. Then there is a choice:
- If the finally block completes normally, then the
try statement completes abruptly for reason R.- If the
finally block completes abruptly for reason S, then thetry statement completes abruptly for reason S (and reason R is discarded).
JLS 14.17退货声明
1
2 ReturnStatement:
return Expression(opt) ;A
return statement with noExpression attempts to transfer control to the invoker of the method or constructor that contains it.A
return statement with anExpression attempts to transfer control to the invoker of the method that contains it; the value of theExpression becomes the value of the method invocation.The preceding descriptions say"attempts to transfer control" rather than just"transfers control" because if there are any
try statements within the method or constructor whosetry blocks contain thereturn statement, then anyfinally clauses of thosetry statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of afinally clause can disrupt the transfer of control initiated by areturn statement.
除了其他响应之外,重要的是指出"finally"有权重写try..catch块的任何异常/返回值。例如,以下代码返回12:
1 2 3 4 5 6 7 8 | public static int getMonthsInYear() { try { return 10; } finally { return 12; } } |
同样,以下方法不会引发异常:
1 2 3 4 5 6 7 8 | public static int getMonthsInYear() { try { throw new RuntimeException(); } finally { return 12; } } |
当以下方法确实抛出它时:
1 2 3 4 5 6 7 8 | public static int getMonthsInYear() { try { return 12; } finally { throw new RuntimeException(); } } |
我对上面的例子做了一些修改-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
以上代码输出:
finally trumps return.
2
这是因为当执行
执行
如果您将在Eclipse中调试此代码,那么在执行
下面是对凯文答案的详细阐述。重要的是要知道要返回的表达式是在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
输出:
1 2 3 | X finally trumps return... sort of 0 |
这就是最后一个街区的全部想法。它让你确保你做清理,否则可能会被跳过,因为你回来,当然,还有其他事情。
最终调用不管尝试中发生什么(除非您调用EDCOX1 1)或Java虚拟机出于其他原因开机。
一个合乎逻辑的思考方法是:
最后总是执行,除非有异常程序终止(如调用System.Exit(0))。所以你的系统会被打印出来
最后一次返回将丢弃任何异常。http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
最后一个块总是被执行,除非有异常的程序终止,要么是由于JVM崩溃,要么是由于调用
除此之外,finally块中返回的任何值都将覆盖finally块执行之前返回的值,因此在使用try finally时,请注意检查所有退出点。
不,不一定只有一个例外//退出系统(0);在finally块阻止最终执行之前。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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"); } } } |
最后总是运行,这就是关键所在,仅仅因为它出现在返回后的代码中并不意味着它就是这样实现的。Java运行时有责任在退出EDCOX1"1"块时运行此代码。
例如,如果您有以下内容:
1 2 3 4 5 6 7 8 |
运行时将生成如下内容:
1 2 3 4 5 |
如果抛出未捕获的异常,将运行
这是因为您将i的值指定为12,但没有将i的值返回给函数。正确的代码如下:
1 2 3 4 5 6 7 8 9 10 | public static int test() { int i = 0; try { return i; } finally { i = 12; System.out.println("finally trumps return."); return i; } } |
Answer is simple YES.
输入:
1 2 3 4 5 6 7 8 |
输出:
1 2 | catch finally |
因为除非调用
是的,它会被呼叫的。这就是使用finally关键字的关键所在。如果从try/catch块中跳出可以跳过finally块,则与将system.out.println放在try/catch之外相同。
是的,finally块始终执行。大多数开发人员使用这个块来关闭数据库连接、结果集对象、语句对象,并使用到Java Hibernate中回滚事务。
简而言之,在官方Java文档中(点击这里),
If the JVM exits while the try or catch code is being executed, then
the finally block may not execute. Likewise, if the thread executing
the try or catch code is interrupted or killed, the finally block may
not execute even though the application as a whole continues.
考虑以下程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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"); } } } |
对于Java1.8162,上面的代码块给出以下输出:
1 2 3 4 5 | -abc- ---AGAIN--- -abc-xyz-abc- ---PRINT THE RESULT--- -abc-xyz-abc-xyz |
这意味着使用
1 2 3 4 5 6 7 8 9 10 11 12 | 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. } } |
是的,会的。无论在try或catch块中发生什么,除非调用了System.exit()或JVM崩溃。如果块中有任何RETURN语句,则最终将在该RETURN语句之前执行。
是的。唯一不会发生的情况是JVM退出或崩溃
是的,因为没有控制语句可以阻止执行
下面是一个参考示例,其中将执行所有代码块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | | 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 | |
在下面的变体中,将跳过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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--; } } |
当然,样板客户会跟踪他们的状态。此示例返回带有
1 2 3 4 5 6 7 8 9 10 | 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 } } |
如果不处理异常,在终止程序之前,JVM将执行finally块。只有当程序的正常执行因以下原因导致Mean终止程序时,它才会执行。
导致导致进程中止的致命错误。
由于内存损坏而终止程序。
通过调用System.Exit()。
如果程序进入无限循环。
1 2 3 4 5 6 7 8 9 10 | 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 } |
最后一个块阻止执行…
- 当你打电话给
System.exit(0); 时 - 如果JVM退出。
- JVM中的错误
这在任何语言中都是正确的…finally总是在返回语句之前执行,不管返回在方法体中的什么位置。如果不是这样的话,最后一块就没有什么意义了。
在下列情况下,
案例1:
在执行
案例2:
当您的JVM/线程崩溃时。
案例3:
当手动停止执行时。
我试过了,它是单螺纹的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
主线程将永远处于等待状态,因此最终不会被调用,
所以控制台输出不会打印字符串:
与@stephen c达成一致,上面的示例是这里提到的第三个案例之一:
在下面的代码中添加更多这样的无限循环可能性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 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"); } } } |
案例2:如果JVM首先崩溃
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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); } } |
裁判:你怎么让一个合资企业破产?
案例6:如果finally块将由守护进程线程执行,并且所有其他非守护进程线程在finally被调用之前退出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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("-------------------------------------------------"); } } |
输出:这不会打印"finally",这意味着"daemon thread"中的"finally block"没有执行
1
2
3
4
5
6
7
8
9
10
11
12
13 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
添加到@vibhash的答案中,因为没有其他答案可以解释在如下可变对象的情况下会发生什么。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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"); } } |
意志输出
1 sbupdated
是的,写在这里
If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.
除了关于在最后替换try块中的返回的要点外,异常也是如此。抛出异常的finally块将替换从try块中抛出的返回或异常。
在一些独特的场景中,返回后将不会调用finally块:如果首先调用System.Exit(),或者如果JVM崩溃。
让我试着用最简单的方法回答你的问题。
规则1:finally块始终运行(尽管也有例外。但我们还是坚持一段时间吧。)
规则2:当控件离开try或catch块时,finally块中的语句将运行。控件的传输可能是由于正常执行、执行break、continue、goto或return语句,或异常的产生。
如果返回语句是特定的(因为它的标题),控件必须离开调用方法,因此调用相应的try finally结构的finally块。返回语句在finally块之后执行。
如果finally块中也有一个RETURN语句,那么它肯定会覆盖try块中挂起的语句,因为它清除了调用堆栈。
你可以在这里找到更好的解释:http://msdn.microsoft.com/en-us/…这个概念在所有高级语言中都是相同的。
并不总是
Java语言规范描述了如何尝试catch catch并尝试catch块在1420.2中工作。在任何地方,它都不会指定始终执行finally块。但是,对于try catch finally和try finally块完成的所有情况,它都指定必须在完成之前最终执行。
1 2 3 4 5 6 7 | 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). |
JLS不保证在代码之后执行FIN。JLS保证,如果执行代码和下一个代码,那么fin将始终在代码之后和下一个代码之前执行。
为什么jls不能保证在try块之后始终执行finally块?因为这是不可能的。在完成try块之后,但在执行finally块之前,JVM不太可能会中止(终止、崩溃、关机)。JLS对此无能为力。
因此,对于其正确行为依赖于finally块的任何软件,总是在其try块完成后执行。
try块中的返回与此问题无关。如果在try catch finally之后执行到代码,则可以保证finally块之前已经执行过,无论在try块内是否返回。
因为在任何情况下都会调用final。您没有异常,它仍然被调用,捕获异常,它仍然被调用
是的,它将始终调用,但在一种情况下,使用System.Exit()时它不会调用
1 2 3 4 5 6 7 8 | 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. } |
如果抛出异常,则最终运行。如果未引发异常,则最终运行。如果捕获到异常,则最终运行。如果未捕获异常,则最终运行。
只有当JVM退出时,它才不运行。
试试这段代码,你会明白代码在finally块被执行后返回语句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
与以下代码相同:
1 2 3 4 5 6 7 8 9 10 | static int f() { while (true) { try { return 1; } finally { break; } } return 2; } |
F将返回2!
无论异常处理与否,finally块始终执行。如果在try block之前发生异常,finally块将不会执行。
我对不同论坛上提供的所有答案感到非常困惑,并决定最终进行编码和查看。输出是:
即使在try and catch块中有返回,也将执行finally。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
产量
try
Print me FINALLY
在正常的执行过程中考虑这一点(即不引发任何异常):如果方法不是"void",则它总是显式返回某些内容,但最终总是得到执行
如果在嵌套的finally块中引发异常,finally也可以提前退出。编译器会警告您,finally块没有正常完成,或者给出一个错误,说明您有无法访问的代码。只有当throw不在条件语句后面或循环内时,才会显示不可访问代码的错误。
1 2 3 4 5 6 7 8 9 | try{ }finally{ try{ }finally{ //if(someCondition) --> no error because of unreachable code throw new RunTimeException(); } int a = 5;//unreachable code } |
最后总是在末尾调用
当您尝试时,它执行一些代码,如果在尝试中发生了什么,那么catch将捕获该异常,您可以打印一些mssg或抛出一个错误,然后执行最后的块。
最后,通常在清理时使用,例如,如果使用Java中的扫描器,则可能会关闭扫描仪,因为它会导致其他问题,例如无法打开某些文件。
finally块始终被执行,即使您在try块中放置了一个RETURN语句。finally块将在返回语句之前执行。