1. finally块一定会被执行么
并不是,只有与 finally 相对应的 try 语句块得到执行的情况下,finally 语句块才会执行。
① 在 try 语句块之前返回(return)或者抛出异常,所以 try 对应的 finally 语句块没有执行,finally也不会执行
public static int test() {
int i = 1;
// if(i == 1)
// return 0;
System.out.println("the previous statement of try block");
i = i / 0;
try {
System.out.println("try block");
return i;
} finally {
System.out.println("finally block");
}
}
② 当一个线程在执行 try 语句块或者 catch 语句块时被打断(interrupted)或者被终止(killed)finally也不会执行
2. 一些规则
finally 语句块在 try 语句块中的 return 语句之前执行
public class Test {
public static void main(String[] args) {
try {
System.out .println("try block");
return ;
} finally {
System.out .println("finally block");
}
}
}
finally 语句块在 catch 语句块中的 return 语句之前执行
public static int test(){
int i = 1;
try {
System.out.println("try block");
i = 1 / 0;
return 1;
}catch (Exception e){
System.out .println("exception block");
return 2;
}finally {
System.out .println("finally block");
}
}
也就是说finally 语句块应该是在控制转移语句之前执行,控制转移语句除了 return 外,还有 break 和 continue,throw 语句也属于控制转移语句
其中 return 和 throw 把程序控制权转交给它们的调用者(invoker),而 break 和 continue 的控制权是在当前方法内转移
try 或者 catch 语句块会保留其返回值到本地变量表
public static void main(String[] args) {
System.out .println("return value of getValue(): " + getValue ());
}
public static int getValue() {
int i = 1;
try {
return i;
} finally {
i++;
}
}
上面代码的执行结果为1,这是因为Java 虚拟机会把 finally 语句块作为 subroutine直接插入到 try 语句块或者 catch 语句块的控制转移语句之前。但是在执行 subroutine(也就是 finally 语句块)之前,try 或者 catch 语句块会保留其返回值到本地变量表(Local Variable Table)中。待 subroutine 执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过 return 或者 throw 语句将其返回给该方法的调用者(invoker)。
请注意,前文中我们曾经提到过 return、throw 和 break、continue 的区别,对于这条规则(保留返回值),只适用于 return 和 throw 语句,不适用于 break 和 continue 语句,因为它们根本就没有返回值