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
可惜。。。字节码没看懂啊。。。唉。。。留帖,以后再说吧。唉。。