finally中的语句不是一定会执行
首先若在执行finally对应的try语句之前方法就执行了return,那么finally将不会执行
其次,若执行到了finally对应的try语句,如果在try中的return语句之前执行了System.exit(0),则java虚拟机退出,finally语句不执行。
若在执行try语句时,所在线程被杀死,那么finally语句同样不会执行。
try,catch,finally的执行顺序
基本顺序是try>catch>finally
关于finally语句和return语句的关系
public class FinallyTest1 {
public static void main(String[] args) {
System.out.println(test1());
}
public static int test1() {
int b = 20;
try {
System.out.println("try block");
return b += 80;
}
catch (Exception e) {
System.out.println("catch block");
}
finally {
System.out.println("finally block");
if (b > 25) {
System.out.println("b>25, b = " + b);
}
}
return b;
}
}
运行结果是
try block
finally block
b>25, b = 100
100
说明return语句已经执行了再去执行finally语句,不过并没有直接返回,而是等finally语句执行完了再返回结果。在字节码中的体现是:return语句的结果先放入本地变量表中,等finally中的语句执行完再从本地变量表拿出结果返回。
public class FinallyTest1 {
public static void main(String[] args) {
System.out.println(test11());
}
public static String test11() {
try {
System.out.println("try block");
return test12();
} finally {
System.out.println("finally block");
}
}
public static String test12() {
System.out.println("return statement");
return "after return";
}
}
运行结果:
try block
return statement
finally block
after return
在这个例子中,先执行test12,然后将test12的返回值“after return”保存在本地变量表中,等finally语句执行完后,再将“after return”返回给main函数输出。
finally中有return语句的情况
public class FinallyTest2 {
public static void main(String[] args) {
System.out.println(test2());
}
public static int test2() {
int b = 20;
try {
System.out.println("try block");
return b += 80;
} catch (Exception e) {
System.out.println("catch block");
} finally {
System.out.println("finally block");
if (b > 25) {
System.out.println("b>25, b = " + b);
}
return 200;
}
// return b;
}
}
运行结果:
try block
finally block
b>25, b = 100
200
这说明finally里的return直接返回了,就不管try中是否还有返回语句,这里还有个小细节需要注意,finally里加上return过后,finally外面的return b就变成不可到达语句了,也就是永远不能被执行到,所以需要注释掉否则编译器报错。
finally中修改返回值的情况
public class FinallyTest3 {
public static void main(String[] args) {
System.out.println(test3());
}
public static int test3() {
int b = 20;
try {
System.out.println("try block");
return b += 80;
} catch (Exception e) {
System.out.println("catch block");
} finally {
System.out.println("finally block");
if (b > 25) {
System.out.println("b>25, b = " + b);
}
b = 150;
}
return 2000;
}
}
运行结果:
try block
finally block
b>25, b = 100
100
和下面的例子:
import java.util.*;
public class FinallyTest6
{
public static void main(String[] args) {
System.out.println(getMap().get("KEY").toString());
}
public static Map<String, String> getMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("KEY", "INIT");
try {
map.put("KEY", "TRY");
return map;
}
catch (Exception e) {
map.put("KEY", "CATCH");
}
finally {
map.put("KEY", "FINALLY");
map = null;
}
return map;
}
}
运行结果:
FINALLY
这里应该和上面提到的本地变量表有关,finally中修改的和try中赋值的不是同一个变量,而引用类型的修改有效,因为其存储区域在堆中。