tryfinally和return的执行顺序是什么样的?
之前看过一篇关于return和finally执行顺序的文章,仅在Java的语言层面做了分析,其实我倒觉得直接看bytecode可能来的更清晰一点。
先看一个只有tryfinally,没有catch的例子。publicclassDemoTryFinlly{publicvoidtryFinally(){try{tryItOut();}finally{wrapItUp();}}publicvoidtryItOut(){}publicvoidwrapItUp(){}}}
通过javapcDemoTryFinlly来查看它的字节码。publicvoidDemoTryFinlly();Code:0:aload01:invokevirtual2MethodtryItOut:()V4:aload05:invokevirtual3MethodwrapItUp:()V8:goto1811:astore112:aload013:invokevirtual3MethodwrapItUp:()V16:aload117:athrow18:returnExceptiontable:fromtotargettype0411any
如果没有抛出异常,那么它的执行顺序为0:aload01:invokevirtual2MethodtryItOut:()V4:aload05:invokevirtual3MethodwrapItUp:()V18:return
如果抛出了异常,JVM会在Exceptiontable:fromtotargettype0411any
中进行控制跳转。如果是位于0到4字节之间的命令抛出了任何类型(anytype)的异常,会跳转到11字节处继续运行。11:astore112:aload013:invokevirtual316:aload117:athrow
astore1会把抛出的异常对象保存到localvariable数组的第二个元素。下面两行指令用来调用成员方法wrapItUp。12:aload013:invokevirtual3
最后通过16:aload117:athrow
重新抛出异常。
通过以上分析可以得出结
在tryfinally中,try块中抛出的异常会首先保存在localvariable中,然后执行finally块,执行完毕后重新抛出异常。
如果我们把代码修改一下,在try块中直接return。
tryreturnfinallypublicvoidDemoTryFinlly(){try{tryItOut();return;}finally{wrapItUp();}}
通过javapcDemoTryFinlly来查看它的字节码。0:aload01:invokevirtual2MethodtryItOut:()V4:aload05:invokevirtual3MethodwrapItUp:()V8:return9:astore110:aload011:invokevirtual3MethodwrapItUp:()V14:aload115:athrow
可以看出finally块的代码仍然被放到了return之前。
如果try块中有returnstatement,一定是finally中的代码先执行,然后return。
给上面的代码加一个catch块publicvoidDemoTryFinlly(){try{tryItOut();}catch(TestExce){handleExc(e);}finally{wrapItUp();}}0:aload01:invokevirtual24:aload05:invokevirtual38:goto3111:astore112:aload013:aload114:invokevirtual517:aload018:invokevirtual321:goto3124:astore225:aload026:invokevirtual329:aload230:athrow31:returnExceptiontable:fromtotargettype0411ClassTestExc0424any111724any
通过Exceptiontable可以看出:catch监听04字节类型为TextExc的异常。finally为04以及1117字节任何类型的异常。
也就说catchblock本身也在finallyblock的管辖范围之内。
如果catchblock中有returnstatement,那么也一定是在finallyblock之后执行。