Java中为什么finally语句块一定会被执行?

来源:互联网 发布:墨脱公路沥青路面数据 编辑:程序博客网 时间:2024/05/16 19:22

通过阅读JVM规范,得知编译器是通过冗余来实现finally语句块的。我们可以写段代码做一个验证。

JDK版本:8
如下面的代码:

import java.io.*;public class Main {    public static void main(String[] args) {        try {            foo();        } catch (IOException e) {            int a = 100;        } catch (Exception e) {            int b = 200;        } finally {            int c = 300;        }    }    public static void foo() throws IOException {    }}

根据finally的语义,我们可以确定int c = 300这行代码一定会被执行。我们可以用javap -v Main来看看这段代码对应的字节码:

Code:      stack=1, locals=5, args_size=1         0: invokestatic  #2                  // Method foo:()V         3: sipush        300         6: istore_1         7: goto          41        10: astore_1        11: bipush        100        13: istore_2        14: sipush        300        17: istore_1        18: goto          41        21: astore_1        22: sipush        200        25: istore_2        26: sipush        300        29: istore_1        30: goto          41        33: astore_3        34: sipush        300        37: istore        4        39: aload_3        40: athrow        41: return

其中,偏移量为14、17, 26、29, 和34、37的字节码就是int c = 300对应的字节码。sipush 300意为将300压入操作数栈,astore_N意为将操作数栈顶元素保存到本地变量表中的第N个slot中。

由此我们可以清楚地看出,编译器确实是在每个catch语句块后都添加了finally块中的字节码, try块的最后也有int c = 300字节码的冗余。如果翻译成Java代码应该这样的:

public static void main(String[] args) {        try {            foo();            int c = 300; // 冗余        } catch (IOException e) {            int a = 100;            int c = 300; // 冗余        } catch (Exception e) {            int b = 200;            int c = 300; // 冗余        } finally {            int c = 300;        }    }

由此可知,我们在写代码时,如果finally块中的代码过多会导致字节码条数”膨胀”,因为finally中的字节码会被”复制”到try块和所有的catch块中。

0 0
原创粉丝点击