java语句的try-catch-finally执行过程中,finally语句块中如果操作了return语句的变量,它对方法的返回值是没有影响的,通过javap分析生成的字节码可以知道,在正常代码块执行完成后,会将需要返回的值存储到单独的局部变量中,而finally操作的局部变量仍然是返回值最初存入的局部变量。由于返回值做了备份,finally对原局部变量的重定向(如果是引用类型),或者修改(基础类型),不会对方法的返回值产生影响。
finally语句会在return语句之前执行,是因为java文件编译过程中已经对try-catch-finally语句做了处理:编译后方法的出口有三种,第一种是正常的try分支,它的字节码内容是java代码中try的语句加上finally的语句;第二种是catch分支,内容=java代码的catch语句+finally语句;第三种是其他异常,内容=finally语句+athrow。
简单类Source源码:
public class Source {
private Source parent;
private String id;
private String name;
private List<Source> children;
public Source(String n){
this.id = n;
}
}
测试类Test:
public class Test {
public static void main(String[] args) {
Source c = get();
System.out.println(c ==null);
System.out.println(c.getId());
}
public static Source get(){
Source source =null;
try{
source = new Source("1");
return source;
}catch (IndexOutOfBoundsException e){
return null;
}finally{
source = new Source("2");
}
}
}
javap -c Test命令查看字节码内容,分析如下:
从字节码看,就很容易明白为什么finally语句并不能对返回值造成影响了。Test语句的执行结果如下,finally虽然对source重新new了,但是作为返回值的source引用已经被备份到了1号局部变量了,所以返回值的引用地址是固定的,同时catch分支也是一样。因为finally语句是每个语句块中最后一部分执行的,所以在finally写return语句有出错的风险,finally里面的return必定会改变正常分支中的返回值。所以在finally中写入return代码,编译器会给出警告的,应该加以重视。
false
1