之前看过一篇关于returnfinally运行顺序的文章。仅在Java的语言层面做了分析。事实上我倒认为直接看bytecode可能来的更清晰一点。

近期一直在看Java虚拟机规范。发现直接分析bytecode更能加深对Java语言的理解。

先看一个仅仅有try-finally。没有catch的样例。

try - finally

public class ExceptionTest {
public void tryFinally() {
try {
tryItOut();
} finally {
wrapItUp();
}
} // auxiliary methods
public void tryItOut() { } public void wrapItUp() {}
}

通过javap -c ExceptionTest来查看它的字节码。

public void tryFinally();
Code:
0: aload_0
1: invokevirtual #2 // Method tryItOut:()V
4: aload_0
5: invokevirtual #3 // Method wrapItUp:()V
8: goto 18
11: astore_1
12: aload_0
13: invokevirtual #3 // Method wrapItUp:()V
16: aload_1
17: athrow
18: return
Exception table:
from to target type
0 4 11 any

假设没有抛出异常,那么它的运行顺序为

0: aload_0
1: invokevirtual #2 // Method tryItOut:()V
4: aload_0
5: invokevirtual #3 // Method wrapItUp:()V
18: return

假设抛出了异常,JVM会在

Exception table:
from to target type
0 4 11 any

中进行控制跳转。假设是位于0到4字节之间的命令抛出了不论什么类型(any type)的异常,会跳转到11字节处继续执行。

11: astore_1
12: aload_0
13: invokevirtual #3
16: aload_1
17: athrow

astore_1会把抛出的异常对象保存到local variable数组的第二个元素。

以下两行指令用来调用成员方法wrapItUp

12: aload_0
13: invokevirtual #3

最后通过

16: aload_1
17: athrow

又一次抛出异常。

通过以上分析能够得出结论

在try-finally中,try块中抛出的异常会首先保存在local variable中。然后运行finally块,运行完成后又一次抛出异常。


假设我们把代码改动一下。在try块中直接return。

try - return - finally

public void tryFinally() {
try {
tryItOut();
return;
} finally {
wrapItUp();
}
}

”反汇编“一下:

 0: aload_0
1: invokevirtual #2 // Method tryItOut:()V
4: aload_0
5: invokevirtual #3 // Method wrapItUp:()V
8: return
9: astore_1
10: aload_0
11: invokevirtual #3 // Method wrapItUp:()V
14: aload_1
15: athrow

能够看出finally块的代码仍然被放到了return之前。

假设try块中有return statement。一定是finally中的代码先运行,然后return。

JVM规范是这么说的

Compilation of a try-finally statement is similar to that of try-catch. Pior to transferring control outside the
try statement, whether that transfer is normal or abrupt, because an exception has been thrown, the
finally clause must first be execute.


try - catch - finally

给上面的代码加一个catch块

public void tryCatchFinally() {
try {
tryItOut();
} catch (TestExc e) {
handleExc(e);
} finally {
wrapItUp();
}
}

javap一下

public void tryCatchFinally();
Code:
0: aload_0
1: invokevirtual #2
4: aload_0
5: invokevirtual #3
8: goto 31
11: astore_1
12: aload_0
13: aload_1
14: invokevirtual #5
17: aload_0
18: invokevirtual #3
21: goto 31
24: astore_2
25: aload_0
26: invokevirtual #3
29: aload_2
30: athrow
31: return
Exception table:
from to target type
0 4 11 Class TestExc
0 4 24 any
11 17 24 any

通过Exception table能够看出:

  • catch监听 0 ~ 4 字节类型为TextExc的异常。
  • finally为 0 ~ 4 以及 11 ~ 17 字节不论什么类型的异常。

也就说 catch block 本身也在 finally block 的管辖范围之内。假设
catch block 中有 return statement,那么也一定是在
finally block
之后运行。


查看原文 http://www.liangfeizc.com/blog/article/32/

用bytecode来看try-catch-finally和return的更多相关文章

  1. java中 try catch finally和return联合使用时,代码执行顺序的小细节

    代码1测试 public static void main(String[] args) { aa(); } static int aa() { try { int a=4/0; } catch (E ...

  2. try catch finally 和return

    结论:1.不管有木有出现异常,finally块中代码都会执行:2.当try和catch中有return时,finally仍然会执行:3.finally是在return后面的表达式运算后执行的(此时并没 ...

  3. try catch finally中return的执行顺序

    下面说一下try{ } catch{}中有return的情况 究竟是哪个return起作用的 话不多说 上代码 1 try中有return的情况 //普通方法 public static int hh ...

  4. Java的finally语句在try或catch中的return语句执行之后还是之前?

    import java.util.HashMap; import java.util.Map; public class FinallyDemo1 { public static void main( ...

  5. try catch 语句中有return 的各类情况

    在牛客上做java题时遇到过多到关于try catch语句的问题,看了很多答案解析,在这里记录一下. 首先给出一道题目: 下面代码的运行结果为? A.catch语句块 和是43 B.编译异常 C.fi ...

  6. try catch中的return与finally

    try catch中的return与finally 代码为 public class Test{ public int add(int a,int b){ try { return a+b; } ca ...

  7. try,catch,finally含return时的执行顺序及丢失的伪例

    最近面试遇到一个之前也看到过但没去看一下的问题.就是有return情况下的try,catch,finally的执行顺序. 今天写了下. 先看顺序问题.总结如下: 一:finally中没有写return ...

  8. try,catch,finally与return

    package com.zl.test; // try catch finally 内有returnpublic class Demo { public static void main(String ...

  9. 关于try...catch...finally中return的疑惑

    原文:http://www.cnblogs.com/and_he/archive/2012/04/17/2453703.html 关于try...catch...finally里面的return一直是 ...

随机推荐

  1. Servlet过滤器——使用过滤器禁止浏览器缓存页面

    1.概述 IE缓存虽然能提高已储存网站的访问速度,但是过度的IE缓存会影响浏览器的响应速度.同时还可能为网站的运行带来一些不必要的麻烦.例如:可能会因为浏览器缓存的应用,而导致Web服务器不能准确的计 ...

  2. greatis很不错,出售源代码

    http://www.greatis.com/delphicb/ 特别是: http://www.greatis.com/delphicb/imgedit/

  3. 结构体的序列和还原(使用Move方法)

    // 定义结构体 typeTmyRec= recordname:string[10];password:string[10];end; function RawToBytes(const AValue ...

  4. boost.asio包装类st_asio_wrapper开发教程(2014.5.23更新)(一)-----转

    一:什么是st_asio_wrapper它是一个c/s网络编程框架,基于对boost.asio的包装(最低在boost-1.49.0上调试过),目的是快速的构建一个c/s系统: 二:st_asio_w ...

  5. hadoop深入研究:(五)——Archives

    转载请注明来源地址:http://blog.csdn.net/lastsweetop/article/details/9123155 简介 我们在hadoop深入研究:(一)——hdfs介绍里已讲过, ...

  6. Shell 传递参数

    Shell 传递参数 向脚本传递参数,格式为:$n. 向脚本传递三个参数,并分别输出: echo "Shell 传递参数实例!"; echo "第一个参数为:$1&quo ...

  7. android使用篇(四) 注解依赖注入IOC实现绑定控件

    在android使用篇(三) MVC模式中提到一个问题: 1) 视图层(View):一般採用XML文件进行界面的描写叙述,使用的时候能够很方便的引入,可是用xml编写了,又须要在Acitvity声明而 ...

  8. 谈VC++对象模型

    一个C++程序员,想要进一步提升技术水平的话,应该多了解一些语言的语意细节.对于使用VC++的程序员来说,还应该了解一些VC++对于C++的诠释.Inside the C++ Object Model ...

  9. 改动Oracle GoldenGate(ogg)各个进程的读检查点和写检查点

    请注意:请谨慎改动Oracle GoldenGate(ogg)各个进程的读检查点和写检查点. 请确保已经 掌握 ogg 各个进程的读检查点和写检查点的详细含义. BEGIN {NOW | yyyy-m ...

  10. 参数传递方法(Delphi1.0与win16API使用pascal方法,即从左到右)

    参数传递方法李维的InsideVCL<第一章>中提到Windows定义的回调函数typedef LRESULT (CALLBACK*WNDPROC)(HWND,UNIT,WPARAM,LP ...