something()
是什么,finally
语句块总是会被执行?try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
something()
是什么,finally
语句块总是会被执行?try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
是的,在执行try
或catch
代码块后,finally
将被调用。
唯一不会调用finally
的情况是:
System.exit()
Runtime.getRuntime().halt(exitStatus)
try
或catch
块中出现无法中断、无法终止的语句,例如无限循环等kill -9 <pid>
finally
块将由守护线程执行,并且所有其他非守护线程在调用finally
之前退出thread.stop()
并不一定能够阻止finally
代码块的执行。 - Piotr Findeisenfinally
块将在try
块之后被调用,且在控制权传递到下一条语句之前被执行。这与try
块涉及无限循环且finally
块实际上从未被调用是一致的。 - Andrzej Doyle示例代码:
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int test() {
try {
return 0;
}
finally {
System.out.println("something is printed");
}
}
输出:
something is printed.
0
finally
语句块中的语句替换为return 2;
(编译器错误),其它行为与上述描述相同。 - Alexander Pacha此外,虽然这是一个不良的实践方式,但如果 finally 代码块中存在 return 语句,则会覆盖常规代码块中的任何其他 return。也就是说,以下代码块将返回 false:
try { return true; } finally { return false; }
在 finally 块中抛出异常也是同样的道理。
以下是Java语言规范官方的说法。
14.20.2. try-finally和try-catch-finally的执行
带有finally块的try语句的执行顺序为:首先执行try语句块,然后进行选择:
- 如果try语句块的执行正常完成,[...]
- 如果由于抛出值V而使try语句块的执行异常终止,[...]
- 如果try语句块由于任何其他原因R而异常地完成,则执行finally块。随后进行选择:
- 如果finally块的执行正常完成,则try语句以原因R异常终止。
- 如果finally块由于原因S而异常地完成,则try语句以原因S异常终止(原因R被丢弃)。
return
语句的规范实际上已经明确说明了这一点:
ReturnStatement: return Expression(opt) ;
如果一个
return
语句没有Expression
,则尝试将控制权转移给包含它的方法或构造函数的调用者。如果一个带有
Expression
的return
语句,尝试将控制权转移给包含它的方法的调用者;Expression
的值成为方法调用的返回值。上述描述使用"尝试将控制权转移"而不是只是"转移控制权",因为如果方法或构造函数中有任何
try
语句,其try
块包含return
语句,则在将控制权转移到方法或构造函数的调用者之前,将按最内层到最外层的顺序执行这些try
语句的任何finally
子句。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();
}
}
OutOfMemoryError
错误? ;) - RecursiveExceptionExceptionfinally
块之后使用return retVal
来解决它,尽管这当然假定你抑制了一些其他异常,否则代码将毫无意义。 - Maarten Bodewes这里详细解释了Kevin's answer。需要知道的是,在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");
return 42;
}
}
输出:
X
finally trumps return... sort of
42
return
的值是在finally
之后。计算返回值(这里是printX()
)仍然在其之前。 - AlbertSystem.out.println("finally trumps return... sort of");
替换为 System.out.print("finally trumps return in try"); return 42;
。 - Pacerierreturn
并没有返回某种神奇的延续,只有在调用者打印它或其他操作时才会被执行。无论有任何 try
/catch
或其它情况,printX()
都会在 return
发生之前被调用。 - Christopher Schultz我尝试对上述示例进行了轻微修改 -
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.");
}
}
以上代码输出:
finally优先于return。
2
这是因为当执行return i;
时,i
的值为2。在此之后,执行finally
块,在其中将12赋给i
,然后执行System.out
。
在执行完finally
块后,try
块返回2而不是12,因为此return
语句不再执行。
如果您在Eclipse中调试此代码,则会感到在执行finally
块的System.out
之后,try
块的return
语句再次执行。但实际情况并非如此,它只是简单地返回值2。
i
不是一个基本类型,而是一个整数对象(Integer object),会发生什么? - Yamcha这就是finally代码块的全部意义。它可以确保你进行清理工作,否则这些工作可能会因为你返回而被跳过,当然还有其他原因。
不管try代码块中发生了什么(除非你调用了System.exit(int)
或Java虚拟机由于某些其他原因退出),finally代码块都会被执行。
一个逻辑上的思考方式是:
finally
块都会被执行。因此,你的 System.out
语句将会被打印出来。
finally
;_finalizer_指的是finalize()
方法。 - jaco0646