您的位置:首页 > 其它

finally与return的执行顺序

2016-09-26 22:26 232 查看
都知道,finally的执行特点

1、不管有木有出现异常,finally块中代码都会执行;

2、当try和catch中有return时,finally仍然会执行。

那么问题来了,执行顺序是怎么样的呢?

一个简单的测试类及反编译后的字节码:

public class Test {
publicstatic void main(String[] args) {
System.out.println(test());
}

publicstatic int test() {
try{
System.out.println("Codesin try block.");
return0;
}catch (Exception e) {
System.out.println("Codesin catch block.");
return100;
}finally {
System.err.println("Codesin finally block.");
}
}
}
/*
public static int test();
Code:
0: getstatic #2 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
3: ldc #5 // String Codes in try block.
5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_0
9: istore_0
10: getstatic #7 // Field java/lang/System.err:Ljava/io/PrintStream;
13: ldc #8 // String Codes in finallyblock.
15: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
18: iload_0
19: ireturn
20: astore_0
21: getstatic #2 // Fieldjava/lang/System.out:Ljava/io/PrintStream;
24: ldc #10 // String Codes in catchblock.
26: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: bipush 100
31: istore_1
32: getstatic #7 // Fieldjava/lang/System.err:Ljava/io/PrintStream;
35: ldc #8 // String Codes in finallyblock.
37: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: iload_1
41: ireturn
42: astore_2
43: getstatic #7 // Fieldjava/lang/System.err:Ljava/io/PrintStream;
46: ldc #8 // String Codes in finallyblock.
48: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
51: aload_2
52: athrow
*/

可以将我们编写的代码和编译后的字节码做一下对比:



发现虚拟机为我们做了好多事,它将finally语句块插到try,catch与return语句之间了。这也就是为什么无论异常与否,返回与否,finally都会执行的原因。既然,finally都会执行,那么在finally中return什么就是什么。既然finally前面所有return都是无效的,return还有什么意义呢,所以,实际中finally块是不允许返回的。eclipse编译器会提示warning:finallyblock does not complete normally。

几种情形的测试代码

try{ return; }catch(){} finally{} return;

测试代码:

1.基本数据类型

public static int test1(){
int a = 10;
try{
a = 20;
return a;
}catch(Exception e){
//other codes.
}finally{
a += 5;
//other codes.
}
return a;
}//最终返回值为202.引用数据类型改变引用对象的值
public static StringBuffer test2(){
StringBuffer sb = new StringBuffer("abc");
try{
return sb;
}catch(Exception e){
//other codes.
}finally{
sb.append("DEF");
//other codes.
}
return sb;
}//最终返回中内容为abcDEF3.引用数据类型改变引用对象 
public static StringBuffer test3(){
StringBuffer sb = new StringBuffer("abc");
try{
return sb;
}catch(Exception e){
//other codes.
}finally{
sb = new StringBuffer("DEF");
//other codes.
}
return sb;
}//最终返回值中的内容为abc
在此种情形的测试中可以发现,在finally之前若有return语句,finally对返回变量无论做什么修改,变量本身是不会再变的,比如为基本类型的变量重新赋值,或是为引用类型的变量重新指定引用都是不会记录到返回值中的。但是finally中的语句会执行,那么在finally中对引用类型的变量指向的对象内容是可以修改的,且修改有效。此种情形可以这样理解,遇到return语句,虚拟机为return的值盖了一套房子,房子能随便拆吗?不能。但是房子里面的人是可以变的。基本数据类型和引用类型的变量本身就是房子,引用类型变量指向的对象中的内容就是房子中的人。

有这样一个小测试:

public static int test(int num){
int a = 10;
try{
return a;
}catch(ArithmeticException e){
a = 20;
return a;
}finally{
a = 30;
return a;
}
}1.1 try 块中没有异常时返回值是多少?
1.2 try块中有ArithmeticException异常时返回值是多少?

1.3 try块中有其他异常时返回值是多少?

答案:全部是30.原因是在执行完try块中return之前的代码后,jvm在return之间插入了finally块中的代码,finally块中含有return,那么就直接返回了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: