try...catch...finally...return的四角恋

java里的try...catch...finally的三角恋关系众多程序员必然是不陌生的。但是他们三者再加上一个return的话,就会难倒一大片人吧。以前就对这个知道这个问题,没系统的总结一下,结果今天女神把我问倒了。。so。。。。

下面就分别看一下吧!

case1:finally语句+try中有return:在执行到return的时候,会先执行finally里面的内容,然后再执行行try中的return。

@SuppressWarnings("finally")
    static void test() {
        int x = 1;
        try {
            logger.info("try.....");
            return;
        } finally {
            ++x;
            logger.info("finally.....");
            
        }
    }

输出:

try.....
finally......

case2:case1+finally里也有return语句:try代码块中的return不执行,即在try中遇到return的时候,会先执行finally里面的内容(包括finally里面的return语句)

public static void main(String[] args) {
        logger.info(TryCatchDemo.test1());
    }
    
    @SuppressWarnings("finally")
    static int test1() {
        int x = 1;
        try {
            logger.info("try.....");
            return x;
        } finally {
            x = x + 1;
            logger.info("finally.....");
            return x;
        }
    }

输出:

2014-04-08 16:39:23,311 INFO  [TryCatchDemo.java:23] : try.....
2014-04-08 16:39:23,347 INFO  [TryCatchDemo.java:27] : finally.....
2

好了,接下里是今天的重头戏了,就是偶被女神难倒的问题。

Case3:Important 我在try里return了某一个值,但是我在finally里对这个值进行了修改,那try块里返回的值是什么?先看代码。

    public static void main(String[] args) {
        logger.info(TryCatchDemo.test2());
    }
    @SuppressWarnings("finally")
    static int test2() {
        int x = 1;
        try {
            logger.info("try.....");
            return x;
        } finally {
            ++x;
            logger.info("finally.....");
        }
    }

该代码会输出什么呢?按照我们正常的理解的话,先执行try里的语句,遇到return时候就去执行finally里的语句,然后修改了x的值为2,最后try里的return返回。

可是结果呢?

2014-04-08 16:45:37,548 INFO  [TryCatchDemo.java:62] : try.....
2014-04-08 16:45:37,551 INFO  [TryCatchDemo.java:66] : finally.....
2014-04-08 16:45:37,552 INFO  [TryCatchDemo.java:16] : 1

结果输出的是1。说明finally里面对要返回的值进行修改,没有反应到最终的结果上去!如果是自己发现的问题的话,估计就到时为止了,下次记住就行了,可问这个问题的可是女神啊。so,屌丝决定看下这段代码编译出来的class对应的字节码,看虚拟机内部是如何执行的。

系统的环境是centos 6.4 x64

jdk环境见下图:

我们用javap -verbose TryCatchFinally >> TyrCatchFinally.txt 来把class文件字节码信息重定向到文件中。(javap是jdk自带的反编译工具命令)

这里主要是看test2部分的反编译字节码:

public int test2();
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: iconst_1                将整型常量1压入栈顶
         1: istore_1           //将栈顶的整数出栈,并存入局部变量区的第2个变量
         2: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         5: ldc           #7              将字符串常量压入栈顶  // String try.....
         7: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        10: iload_1          //将局部变量区的第2个变量压入栈
        11: istore_2           //将栈顶的整数出栈,并存入局部变量区的第3个变量
        12: iinc          1, 1
        15: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        18: ldc           #9                  // String finally.....
        20: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        23: iload_2
        24: ireturn
        25: astore_3
        26: iinc          1, 1
        29: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        32: ldc           #9                  // String finally.....
        34: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        37: aload_3
        38: athrow

可惜。。。字节码没看懂啊。。。唉。。。留帖,以后再说吧。唉。。

原文地址:https://www.cnblogs.com/babybluevino/p/3652517.html