字节码指令-深度解析try catch finally的执行顺序

结论:

 

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


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


3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;


4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

 

分析:

引用别人的总结,总结的不错,但是why?学知识不可不求甚解,那就来分析一下

 

<em>public static Integer testTryCatchFinally () {
		Integer result;
		try {
			result = 10/0;
			return result;
		}catch (Exception e) {
			result = 2;
			return result;
		}finally {
			result = 3;
//			return result;
		}
	}</em>

编译后的字节码指令

 

public static java.lang.Integer testTryCatchFinally();
     0  bipush 10	//将单字节的常量值10推送至栈顶
     2  iconst_0	//将int型0推送至栈顶
     3  idiv	//将栈顶两int型数值相除并将结果压入栈顶
     4  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [122]	//调用静态方法
     7  astore_0 [result]	// 将栈顶引用型数值存入第一个本地变量
     8  aload_0 [result]	//将第一个引用类型本地变量推送至栈顶
     9  astore_3	//将栈顶应用型数值存入第四个本地变量
    10  iconst_3	//将int型3推送至栈顶
    11  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [122]	//调用静态方法
    14  astore_0 [result]	// 将栈顶引用型数值存入第一个本地变量
    15  aload_3	//将第四个引用类型本地变量推送至栈顶
    16  areturn	//从当前方法返回对象引用
    17  astore_1 [e]	// 将栈顶引用型数值存入第二个本地变量
    18  iconst_2	//将int型2推送至栈顶
    19  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [122]	//调用静态方法
    22  astore_0 [result]	// 将栈顶引用型数值存入第一个本地变量
    23  aload_0 [result]	//将第一个引用类型本地变量推送至栈顶
    24  astore_3	// 将栈顶引用型数值存入第四个本地变量
    25  iconst_3	//将int型3推送至栈顶
    26  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [122]	//调用静态方法
    29  astore_0 [result]	// 将栈顶引用型数值存入第一个本地变量
    30  aload_3	//将第四个引用类型本地变量推送至栈顶
    31  areturn	//从当前方法返回对象引用
    32  astore_2
    33  iconst_3
    34  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [122]
    37  astore_0 [result]
    38  aload_2
    39  athrow	//将栈顶的异常抛出
      Exception Table:
        [pc: 0, pc: 10] -> 17 when : java.lang.Exception
        [pc: 0, pc: 10] -> 32 when : any
        [pc: 17, pc: 25] -> 32 when : any
      Line numbers:
        [pc: 0, line: 42]
        [pc: 8, line: 43]
        [pc: 10, line: 48]
        [pc: 15, line: 43]
        [pc: 17, line: 44]
        [pc: 18, line: 45]
        [pc: 23, line: 46]
        [pc: 25, line: 48]
        [pc: 30, line: 46]
        [pc: 32, line: 47]
        [pc: 33, line: 48]
        [pc: 38, line: 50]
      Local variable table:
        [pc: 8, pc: 17] local: result index: 0 type: java.lang.Integer
        [pc: 23, pc: 32] local: result index: 0 type: java.lang.Integer
        [pc: 38, pc: 40] local: result index: 0 type: java.lang.Integer
        [pc: 18, pc: 32] local: e index: 1 type: java.lang.Exception
      Stack map table: number of frames 2
        [pc: 17, same_locals_1_stack_item, stack: {java.lang.Exception}]
        [pc: 32, same_locals_1_stack_item, stack: {java.lang.Throwable}]

 

分析字节码指令:

逐一分析

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

观察字节码指令发现,finally字节码指令已经编译到try/catch代码块里


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

观察字节码指令发现,finally字节码指令已经编译到try/catch代码块里,并且return指令是在最后


3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;

上图分析得知,最终load下标为3的变量到栈顶并返回,而不是返回finally的result=3,正常情况返回try块里的result计算结果x,异常返回catch块里的result=2


4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

分析一下指令,finally中有return,try/catch块中编译后无return指令,失效,只返回finally块中的result=3,而不是程序提前退出。

 

<em> public static java.lang.Integer testTryCatchFinally();
     0  bipush 10
     2  iconst_0
     3  idiv
     4  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [122]
     7  astore_0 [result]
     8  goto 21
    11  astore_1 [e]
    12  iconst_2
    13  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [122]
    16  astore_0 [result]
    17  goto 21
    20  pop
    21  iconst_3
    22  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [122]
    25  astore_0 [result]
    26  aload_0 [result]
    27  areturn
      Exception Table:
        [pc: 0, pc: 11] -> 11 when : java.lang.Exception
        [pc: 0, pc: 20] -> 20 when : any
      Line numbers:
        [pc: 0, line: 42]
        [pc: 8, line: 43]
        [pc: 11, line: 44]
        [pc: 12, line: 45]
        [pc: 17, line: 46]
        [pc: 20, line: 47]
        [pc: 21, line: 48]
        [pc: 26, line: 49]
      Local variable table:
        [pc: 8, pc: 11] local: result index: 0 type: java.lang.Integer
        [pc: 17, pc: 20] local: result index: 0 type: java.lang.Integer
        [pc: 26, pc: 28] local: result index: 0 type: java.lang.Integer
        [pc: 12, pc: 20] local: e index: 1 type: java.lang.Exception
      Stack map table: number of frames 3
        [pc: 11, same_locals_1_stack_item, stack: {java.lang.Exception}]
        [pc: 20, same_locals_1_stack_item, stack: {java.lang.Throwable}]
        [pc: 21, same]</em>

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值