finally块总是在Java中执行吗?

考虑到这段代码,我可以绝对确定 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."); } 

是的, finally将在执行try或catch代码块之后调用。

finally不会被召唤的唯一时间是:

  1. 如果你调用System.exit() ;
  2. 如果JVM首先崩溃;
  3. 如果JVM在trycatch块中到达无限循环(或其他一些不可中断的,非终止语句);
  4. 如果操作系统强行终止JVM进程; 例如UNIX上的“kill -9”。
  5. 如果主机系统死亡; 例如电源故障,硬件错误,操作系统恐慌等。
  6. 如果最终块将由守护程序线程执行,并且所有其他非守护程序线程在最终被调用之前退出。

示例代码:

 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块中抛出exception也是一样的。

这是Java语言规范中的官方文字。

14.20.2。 执行try-finally和try-catch-finally

通过首先执行try块来执行具有finally块的try语句。 然后有一个选择:

  • 如果try块的执行正常完成,[…]
  • 如果由于throwV而突然完成try块的执行,[…]
  • 如果try块的执行由于任何其他原因R突然完成,则执行finally块。 然后有一个选择:
    • 如果finally块正常完成,那么try语句突然完成,原因是R。
    • 如果finally块因为原因S而突然完成,则try语句突然完成,原因是S并且原因R被丢弃 )。

return的规范实际上使这个明确:

JLS 14.17返回声明

 ReturnStatement: return Expression(opt) ; 

没有Expression return语句尝试将控制权转移给包含它的方法或构造函数的调用者。

带有Expression return语句尝试将控制权转移给包含它的方法的调用者; Expression的值成为方法调用的值。

前面的描述说“ 尝试转移控制 ”而不仅仅是“ 转移控制 ”,因为如果在try块中包含return语句的方法或构造函数中有任何try语句,那么将执行那些try语句的任何finally子句,在将控制权转移给方法或构造函数的调用者之前,从最里面到最外面的顺序。 突然完成finally子句可以破坏由return语句启动的控制转移。

除了其他响应之外,重要的是要指出’finally’有权通过try..catch块覆盖任何exception/返回值。 例如,以下代码返回12:

 public static int getMonthsInYear() { try { return 10; } finally { return 12; } } 

同样,以下方法不会抛出exception:

 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中调试此代码,那么您会感觉在执行finally块的System.out ,再次执行try块的return语句。 但这种情况并非如此。 它只返回值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虚拟机因其他原因而踢出)。

考虑这一点的合理方式是:

  1. 放置在finally块中的代码必须在try块内发生
  2. 因此,如果try块中的代码尝试返回值或抛出exception,则将项放在“架子上”,直到finally块可以执行
  3. 因为finally块中的代码(按照定义)具有高优先级,所以它可以返回或抛出它喜欢的任何内容。 在这种情况下,“货架上”留下的任何东西都将被丢弃。
  4. 唯一的例外是VM在try块期间完全关闭,例如’System.exit’

最后的回报也会抛弃任何exception。 http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

除非程序exception终止(如调用System.exit(0)..),否则最后总是执行。 所以,你的sysout会打印出来

不,并不总是一个例外情况是// 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"); } } } 

除非由于JVM崩溃或调用System.exit(0)导致程序exception终止,否则始终执行finally块。

最重要的是,finally块中返回的任何值都将覆盖执行finally块之前返回的值,因此在使用try finally时要小心检查所有出口点。

最后总是运行这是整点,只是因为它在返回后出现在代码中并不意味着它是如何实现的。 退出try块时,Java运行时负责运行此代码。

例如,如果您有以下内容:

 int foo() { try { return 42; } finally { System.out.println("done"); } } 

运行时将生成如下内容:

 int foo() { int ret = 42; System.out.println("done"); return 42; } 

如果抛出未捕获的exception,则finally块将运行,exception将继续传播。

因为除非你调用System.exit() (或线程崩溃),否则将始终调用finally块。

简而言之,在官方Java文档(点击这里 )中,写道 –

如果在执行try或catch代码时JVM退出,则finally块可能无法执行。 同样,如果执行try或catch代码的线程被中断或终止,则即使应用程序作为一个整体继续,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; } } 

是的,它会被调用。 这就是拥有finally关键字的重点。 如果跳出try / catch块可能只是跳过finally块,那就像将System.out.println放在try / catch之外一样。

是的,它会。 无论你的try或catch块发生了什么,除非调用System.exit()或JVM崩溃。 如果块中有任何return语句,则最终将在该return语句之前执行。

是的,它会。 只有JVM退出或崩溃才会出现这种情况

是的,最后块总是执行。 大多数开发人员使用此块关闭数据库连接,结果集对象,语句对象以及使用java hibernate来回滚事务。

答案很简单。

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 

这在任何语言中都是正确的…最终将始终在return语句之前执行,无论方法体中返回的位置如何。 如果不是这样的话,那么finally块就没有多大意义了。

因为无论你有什么案例,总是会被调用。 你没有exception,它仍然被调用,捕获exception,它仍然被调用

在正常的执行过程中考虑这一点(即没有抛出任何exception):如果方法不是’void’,那么它总是显式地返回一些东西,但是,最后总是被执行

如果抛出exception,最后运行。 如果没有抛出exception,最后运行。 如果捕获到exception,则最终运行。 如果未捕获exception,则最终运行。

只有当JVM退出时它才会运行。

最后块总是执行是否处理exception。如果在try块之前发生任何exception,则finally块将不会执行。

考虑这一点的合理方式是:

放置在finally块中的代码必须在try块内发生。

因此,如果try块中的代码尝试返回一个值或抛出一个exception,那么该项将被置于“架子上”,直到finally块可以执行为止。因为finally块中的代码具有(按照定义)高优先级,它可以返回或抛出无论喜欢什么。 在这种情况下,“货架上”留下的任何东西都将被丢弃。

唯一的例外是VM在try块期间完全关闭,例如’System.exit’

永远不要从finally块中抛出任何exception

 try { someMethod(); //Throws exceptionOne } finally { cleanUp(); //If finally also threw any exception the exceptionOne will be lost forever } 

这很好,只要cleanUp()永远不会抛出任何exception。 在上面的示例中,如果someMethod()抛出exception,并且在finally块中,cleanUp()也会抛出exception,第二个exception将来自方法,并且原始的第一个exception(正确的原因)将永远丢失。 如果您在finally块中调用的代码可能会抛出exception,请确保您要么处理它,要么记录它。 永远不要让它从最后一块出来。

实际上退出程序(通过调用System.exit()或导致导致进程中止的致命错误:有时在Windows中非正式地称为“热点”或“Dr Watson”)将阻止您的finally块被阻止执行!

没有什么可以阻止我们嵌套try / catch / finally块(例如,将try / finally块放在try / catch块中,反之亦然),这并不是一件不寻常的事情。

考虑以下程序:

 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()); } private static String someString() { try { sb.append("-abc-"); return sb.toString(); } finally { sb.append("xyz"); } } } 

从Java 1.8.162开始,上面的代码块给出了以下输出:

 -abc- ---AGAIN--- -abc-xyz-abc- 

这意味着finally使用释放对象是一个很好的做法,如下面的代码:

 private static String someString() { StringBuilder sb = new StringBuilder(); try { sb.append("abc"); return sb.toString(); } finally { sb = null; } } 

除了最后替换try块中的返回的返回点之外,exception也是如此。 抛出exception的finally块将替换try块内抛出的返回或exception。