前言:一直都以为finally块一定执行,但是在有次的笔试中突然发现,想的太绝对了。
一、笔试题
第一题:
Finally block will always be executed.
A: 正确
B: 错误
第二题:
read the code, write the output
public class Test {
public static int getValue() {
int i = 1;
try {
i++;
return i;
} finally {
i++;
}
}
public static void main(String[] args) {
System.out.println(getValue());
}
}
二、详解
1、误解一,finally一定执行
事实上,存在以下几个情景,都不会执行:
A、未执行到try-finally语句块,比如在try前返回或者抛出异常
B、try-finally语句块中,如果在try或者catch中有System.exit(0);也不会执行finally语句块
C、try-finally中,如果try或者catch语句块被打断或者中止,也不会执行finally语句块
D、守护线程中的finally,如果非守护线程终止,虚拟机kill掉守护线程类似B
public class MainTest {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
System.out.println("daemon thread run");
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
} finally {
System.out.println("finally run");
}
});
thread.setDaemon(true);
thread.start();
System.out.println("main exit");
}
}
2、try-catch中返回值,受到finally语句块的影响
就如笔试题第二题,以为是3,实际是2.
实际上,虚拟机会把finally语句块作为 subroutine直接插入到try-catch的控制转移语句之前。但是在执行subroutine之前,会把try-catch中的返回值保留到本地变量表;等执行完subroutine,再恢复保留的返回值到操作数栈中。这条规则只适合retrun和throw,对break和continue无效,以为break和continue本来就没有返回值。