考虑到这一点的代码,我可以绝对肯定的是,finally
块总是执行,不管something()
是什么?
try { something(); return success; } catch (Exception e) { return failure; } finally { System.out.println("I don't know if this will get printed out"); }
jodonnell.. 2565
是的,finally
将在执行try或catch代码块后调用.
唯一try
不会被调用的是:
如果你调用catch
;
如果JVM首先崩溃;
如果JVM在finally
或System.exit()
块中达到无限循环(或其他一些不可中断的,非终止语句);
如果操作系统强行终止JVM进程; 例如UNIX上的"kill -9".
如果主机系统死亡; 例如电源故障,硬件错误,操作系统恐慌等.
如果finally块将由守护程序线程执行,并且所有其他非守护程序线程在最终被调用之前退出.
我们怎么说`finally`块将在*try`块之后调用*,*之前*控制传递给以下语句.这与涉及无限循环的try块一致,因此finally块实际上从未被调用过. (161认同)
实际上`thread.stop()`并不一定会阻止`finally`块被执行. (38认同)
@BinoyBabu - 这是关于终结者,而不是最终阻止 (11认同)
还有另一种情况,当我们使用嵌套的**try-catch-finally**块时 (8认同)
另外,在守护进程线程抛出异常的情况下,最后不会调用block. (5认同)
那么**Runtime#halt**? (3认同)
@AmrishPandey Oracle页面根本没有提到守护进程.另一个(博客)页面讨论了JVM _terminating_,但未能显示与非守护程序线程的任何差异.现实是:在System.exit完成(包括关闭挂钩)或其他终止时,所有线程都会死在它们所站的位置,无论是否守护进程:没有最终以任何方式执行.博主不正确,他们注意到这是一个区别...自己尝试一下. (3认同)
@AmrishPandey“如果守护程序线程抛出异常,则最终块不会被调用”-真的吗?[需要引用],我觉得呢? (2认同)
无限循环并不是"最后将在try块完成时调用"规则的例外.即使在try块中有一个无限循环,finally块仍会*执行***当try块完成***时,像往常一样 - try块只是没有完成.这不是一个特例. (2认同)
问:它总是吗?答:是的,除了......对我而言,这意味着接受的答案应该是否定的.如果总是存在例外,那么它的不存在.它可能在大多数时间运行.但不总是.我很惊讶我是少数几个对此作出反应的人之一. (2认同)
Kevin.. 533
示例代码:
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."); } }
输出:
finally trumps return.
0
对不起,这是一个演示而不是证明.如果您能够证明此示例在所有Java平台上始终以这种方式运行,那么这只是一个证明,并且类似示例也始终以这种方式运行. (19认同)
仅供参考:在C#中,除了将`finally`-clause中的语句替换为`return 2;`不允许(Compiler-Error)之外,行为是相同的. (17认同)
您甚至可以在finally块本身中添加一个return语句,然后它将覆盖之前的返回值.这也神奇地丢弃了未处理的异常.此时,您应该考虑重构代码. (17认同)
这是一个需要注意的重要细节:http://stackoverflow.com/a/20363941/2684342 (15认同)
这并没有真正证明最终胜过回归.从调用者代码打印返回值.似乎没有多大证据. (8认同)
小智.. 375
此外,虽然这是不好的做法,但如果在finally块中有一个return语句,它将胜过常规块中的任何其他返回.也就是说,以下块将返回false:
try { return true; } finally { return false; }
从finally块中抛出异常也是一样的.
是的,finally
将在执行try或catch代码块后调用.
唯一try
不会被调用的是:
如果你调用catch
;
如果JVM首先崩溃;
如果JVM在finally
或System.exit()
块中达到无限循环(或其他一些不可中断的,非终止语句);
如果操作系统强行终止JVM进程; 例如UNIX上的"kill -9".
如果主机系统死亡; 例如电源故障,硬件错误,操作系统恐慌等.
如果finally块将由守护程序线程执行,并且所有其他非守护程序线程在最终被调用之前退出.
示例代码:
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."); } }
输出:
finally trumps return.
0
此外,虽然这是不好的做法,但如果在finally块中有一个return语句,它将胜过常规块中的任何其他返回.也就是说,以下块将返回false:
try { return true; } finally { return false; }
从finally块中抛出异常也是一样的.
这是Java语言规范中的官方文字.
14.20.2.执行try-finally和try-catch-finally
通过首先执行块来执行
try
具有finally
块的语句try
.然后有一个选择:
如果
try
块的执行正常完成,[...]如果
try
块的执行由于throw
值V而突然完成,[...]如果
try
由于任何其他原因R突然完成finally
块的执行,则执行该块.然后有一个选择:
如果finally块正常完成,则该
try
语句突然完成的原因[R .如果
finally
块因原因S而突然完成,则try
语句突然完成,原因为S(并且原因R被丢弃).
return
实际的规范明确指出:
JLS 14.17返回声明
ReturnStatement: return Expression(opt) ;一个
return
语句,没有Expression
尝试将控制权转移给包含它的方法或构造函数的调用者.阿
return
与语句Expression
尝试将控制转移到包含它的方法的调用; 值的值Expression
成为方法调用的值.前面的描述说" 尝试转移控制 "而不仅仅是" 转移控制 ",因为如果
try
方法或构造函数中的任何语句的try
块包含该return
语句,那么finally
这些try
语句的任何子句将按顺序执行,最内层到最外层,在将控制权转移给方法或构造函数的调用者之前.突然完成一个finally
条款可以破坏由return
声明发起的控制权转移.
除了其他响应之外,重要的是要指出'finally'有权通过try..catch块覆盖任何异常/返回值.例如,以下代码返回12:
public static int getMonthsInYear() { try { return 10; } finally { return 12; } }
同样,以下方法不会抛出异常:
public static int getMonthsInYear() { try { throw new RuntimeException(); } finally { return 12; } }
虽然以下方法确实抛出它:
public static int getMonthsInYear() { try { return 12; } finally { throw new RuntimeException(); } }
我尝试了上面的例子,略有修改 -
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."); } }
以上代码输出:
最后胜过回归.
2
这是因为当return i;
执行时i
具有值2.在此之后finally
执行块,其中12被分配i
,然后System.out
执行out.
执行finally
块后,try
块返回2,而不是返回12,因为不会再次执行此return语句.
如果您将调试在Eclipse这个代码,那么你会得到执行后一种感觉System.out
的finally
块中return
的语句try
块被再次执行.但这种情况并非如此.它只返回值2.
这是凯文答案的详细说明.重要的是要知道要返回的表达式之前进行评估finally
,即使之后返回它也是如此.
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"); } }
输出:
X
finally trumps return... sort of
0
这就是最终块的整体想法.它允许您确保进行清理,否则可能会因为您返回而被忽略,当然.
无论 try块中发生了什么,最终都会被调用(除非你打电话System.exit(int)
或Java虚拟机因其他原因而启动).
考虑这一点的合理方式是:
放置在finally块中的代码必须在try块内发生
因此,如果try块中的代码尝试返回值或抛出异常,则将项放在"架子上",直到finally块可以执行
因为finally块中的代码(根据定义)具有高优先级,所以它可以返回或抛出它喜欢的任何内容.在这种情况下,"架子上"留下的任何东西都将被丢弃.
唯一的例外是VM在try块期间完全关闭,例如'System.exit'
除非程序异常终止(如调用System.exit(0)..),否则最后总是执行.所以,你的sysout会打印出来
最后的回报也会抛弃任何异常. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
除非由于JVM崩溃或来自调用而导致程序异常终止,否则始终执行finally块System.exit(0)
.
最重要的是,从finally块中返回的任何值都将覆盖执行finally块之前返回的值,因此在使用try finally时要小心检查所有出口点.
不,并不总是一个例外情况是// System.exit(0); 在finally块阻止最终执行之前.
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运行时有责任在退出try
块时运行此代码.
例如,如果您有以下内容:
int foo() { try { return 42; } finally { System.out.println("done"); } }
运行时将生成如下内容:
int foo() { int ret = 42; System.out.println("done"); return 42; }
如果抛出未捕获的异常,则finally
块将运行,异常将继续传播.
这是因为您将i的值指定为12,但未将i的值返回给函数.正确的代码如下:
public static int test() { int i = 0; try { return i; } finally { i = 12; System.out.println("finally trumps return."); return i; } }
因为除非你调用System.exit()
(或线程崩溃),否则将始终调用finally块.
答案很简单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"); }
OUTPUT:
catch finally
是的,它会被调用.这就是拥有finally关键字的重点.如果跳出try/catch块可能只是跳过finally块,那么就像把System.out.println放在try/catch之外一样.
简而言之,在官方Java文档(点击这里)中,写道 -
如果在执行try或catch代码时JVM退出,则finally块可能无法执行.同样,如果执行try或catch代码的线程被中断或终止,则即使应用程序作为一个整体继续,finally块也可能无法执行.
是的,最后块总是执行.大多数开发人员使用此块关闭数据库连接,结果集对象,语句对象以及还使用java hibernate来回滚事务.
是的,它会的.无论你的try或catch块发生什么,除非调用System.exit()或JVM崩溃.如果块中有任何返回语句,则最终将在该返回语句之前执行.
是的,它会的.只有它不会出现JVM退出或崩溃的情况
添加到@ vibhash的答案,因为没有其他答案解释在如下所示的可变对象的情况下会发生什么.
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 "); } }
会输出
sbupdated
考虑以下程序:
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"); } } }
从Java 1.8.162开始,上面的代码块给出了以下输出:
-abc- ---AGAIN--- -abc-xyz-abc- ---PRINT THE RESULT--- -abc-xyz-abc-xyz
这意味着使用finally
释放对象是一个很好的做法,如下面的代码:
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. } }
这在任何语言中都是正确的...最终将始终在return语句之前执行,无论方法体中返回的位置如何.如果不是这样的话,那么finally块就没有多大意义了.
除了关于最终替换try块中的return的返回点之外,异常也是如此.抛出异常的finally块将替换try块内抛出的返回或异常.
finally
将执行,这是肯定的.
finally
在以下情况下不会执行:
情况1 :
当你执行System.exit()
.
案例2:
当您的JVM /线程崩溃时.
案例3:
当您的执行在手动之间停止时.
Java语言规范描述了try-catch-finally和try-catch块如何在14.20.2中工作.
在任何地方它都没有指定始终执行finally块.但是对于try-catch-finally和try-finally块完成的所有情况,它确实指定在完成之前最终必须执行.
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不保证在CODE之后执行FIN.JLS保证如果执行CODE和NEXT,则FIN将始终在CODE之后和NEXT之前执行.
为什么JLS不保证在try块之后总是执行finally块?因为这是不可能的.在完成try块之后但在执行finally块之前,JVM很可能会被中止(终止,崩溃,断电).JLS无法避免这种情况.
因此,任何因其正常行为而依赖于最终块的软件都会在其尝试块完成后始终执行.
try块中的返回值与此问题无关.如果执行在try-catch-finally之后到达代码,则保证finally块在之前执行,有或没有在try块内返回.
我试过这个,它是单线程的.
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"); } } }
主线程将永远处于等待状态,因此最终永远不会被调用,
所以控制台输出不会打印字符串:after wait()
或finally
同意@Stephen C,上面的例子是第三个案例之一:https://stackoverflow.com/a/65049/2987755
在以下代码中添加更多此类无限循环可能性:
// 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首先崩溃
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); } }
参考:你如何崩溃JVM?
情况6:如果最终块将由守护程序线程执行,并且所有其他非守护程序线程在最终被调用之前退出.
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; SetthreadSet = 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",这意味着"守护程序线程"中的"finally块"没有执行
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
最后Block总是被执行.除非并且直到 System.exit()语句存在(finally块中的第一个语句).
如果system.exit()是第一个语句,那么finally块将不会被执行并且控制来自finally块.每当System.exit()语句进入finally块时,直到该语句最终执行块,并且当System.exit()出现时,控制力完全从finally块中出来.
如果不处理异常,则在终止程序之前,JVM会执行finally块.只有当程序的正常执行失败意味着由于以下原因终止程序时才会执行它.
通过导致致命错误导致进程中止.
由于内存损坏导致程序终止.
通过调用System.exit()
如果程序进入无限循环.
是的,因为没有控制语句可以阻止finally
执行.
这是一个参考示例,其中将执行所有代码块:
| 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 |
在下面的变体中,return x;
将跳过.结果仍然是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--; } }
当然,参考资料会追踪他们的状态.此示例返回一个引用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块:如果首先调用System.exit(),或者JVM崩溃.
让我试着用最简单的方式回答你的问题.
规则1:finally块总是运行(尽管有例外.但是让我们坚持一段时间.)
规则2:当控制离开try或catch块时finally块中的语句运行.控制的转移可以由于正常执行,执行break,continue,goto或return语句或者宣传例外.
如果返回语句具体(因为它的标题),控件必须离开调用方法,因此调用相应的try-finally结构的finally块.return语句在finally块之后执行.
如果finally块中还有一个return语句,它肯定会覆盖try块中挂起的一个,因为它清除了调用栈.
您可以在此处参考更好的解释:http://msdn.microsoft.com/en-us/ ....这个概念在所有高级语言中大致相同.
try
- catch
- finally
是使用异常处理案例的关键词.
正常的解释
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 }
finally块阻止执行......
你打电话的时候 System.exit(0);
如果JVM退出.
JVM中的错误