【转】Java finally语句到底是在return之前还是之后执行?
网上有很多人探讨Java中异常捕获机制try...catch...finally块中的finally语句是不是一定会被执行?很多人都说不是,当然他们的回答是正确的,经过试验,至少有两种情况下finally语句时不会被执行的:
(1)try语句没有被执行到,如在try语句之前就返回了,这样finally语句就不会执行,这也说明了finally语句被执行的必要而非充分条件是:相应的try语句一定被执行到。
(2)在try块中有System.exit(0);这样的语句,System.exit(0);是终止Java虚拟机JVM的,连JVM都停止了,所有都结束了,当然finally语句也不会被执行到。
当然还有很多人探讨Finally语句的执行与return的关系,颇为让人迷惑,不知道finally语句是在try的return之前执行还是之后执行?我也是一头雾水,我觉得他们的说法都不正确,我觉得应该是:finally语句是在try的return语句执行之后,return返回之前执行。这样的说法有点矛盾,也许是我表述不太清楚,下面我给出自己试验的一些结果和示例进行佐证,有什么问题欢迎大家提出来。
1、finally语句在return语句执行之后return返回之前执行的。
 package com.meng.javalanguage.finallytest;
 public class FinallyTest1 {
     public static void main(String[] agrs) {
         System.out.println(test1());
     }
     public static int test1() {
         int b = 20;
         try {
             System.out.println("try block");
             return b += 80;
         }catch(Exception e) {
             System.out.println("catch block");
         }
         finally {
             System.out.println("finally block");
             if(b > 25) {
                 System.out.println("b > 25,b = " + b);
             }
         }
         return b;
     }
 }
运行结果是:

说明return语句已经执行了再去执行finally语句,不过并没有直接返回,而是等finally语句执行完了再返回结果。
如果觉得这个例子不足以说明这个情况的话,下面再加个例子加强证明结论:
 package com.meng.javalanguage.finallytest;
 public class FinallyTest1 {
     public static void main(String[] args) {
         System.out.println(test11());
     }
     public static String test11() {
         try {
             System.out.println("try block");
             return test12();
         } finally {
             System.out.println("finally block");
         }
     }
     public static String test12() {
         System.out.println("return statement");
         return "after return";
     }
 }
运行结果为:

说明try中的return语句先执行了但并没有立即返回,等到finally执行结束后再返回。
这里大家可能会想:如果finally里也有return语句,那么是不是就直接返回了,try中的return就不能返回了?看下面。
2、finally块中的return语句会覆盖try块中的return返回。
 package com.meng.javalanguage.finallytest;
 public class FinallyTest2 {
     public static void main(String[] args) {
         System.out.println(test2());
     }
     @SuppressWarnings("finally")
     public static int test2() {
         int b = 20;
         try {
             System.out.println("try block");
             return b += 80;
         }catch(Exception e) {
             System.out.println("catch block");
         }
         finally {
             System.out.println("finally block");
             if(b > 25) {
                 System.out.println("b > 25, b = " + b);
             }
             return 200;
         }
 //        return b;
     }
 }
运行结果是:

这说明finally里的return直接返回了,就不管try中是否还有没有返回语句。这里还有个小细节需要注意,finally里加上return过后,finally外面的return b;就变成了不可到达的语句,也就是永远不能被执行到,所以需要注释掉否则编译器报错。
这里大家可能又想:如果finally里没有return语句,但修改了b的值,那么try中return返回的是修改后的值还是原值?看下面。
3、如果finally语句中没有return语句覆盖返回值,那么原来的返回值可能因为finally里的修改而改变也可能不变。
测试用例1:
 package com.meng.javalanguage.finallytest;
 public class FinallyTest3 {
     public static void main(String[] args) {
         System.out.println(test3());
     }
     public static int test3() {
         int b = 20;
         try {
             System.out.println("try block");
             return b += 80;
         }catch(Exception e) {
             System.out.println("catch block");
         }
         finally {
             System.out.println("finally block");
             if(b > 25) {
                 System.out.println("b > 25, b = " + b);
             }
             b = 150;
         }
         return 2000;
     }
 }
运行结果是:

测试用例2:
package com.meng.javalanguage.finallytest; import java.util.HashMap;
import java.util.Map; public class FinallyTest6 {
public static void main(String[] args) {
System.out.println(getMap().get("KEY").toString());
} public static Map<String, String> getMap() {
Map<String, String> map = new HashMap<String, String>(); map.put("KEY","INIT"); try {
map.put("KEY", "TRY");
return map;
}catch(Exception e) {
map.put("KEY", "CATCH");
}
finally {
map.put("KEY", "FINALLY");
map = null;
} return map;
}
}
运行结果是:
为什么测试用例1中finally里的b = 150;并没有起到作用而测试用例2中finally的map.put("KEY","FINALLY");起了作用而map = null;却没起作用呢?这就是Java到底是传值还是传址的问题了,return语句已经执行了:
1)再对b操作(b = 150;)相当于参数传递,操作的b是形式参数,不影响实际参数的值;
2)对map的操作(map = null)与1)同理,同样不影响实际参数的值;
3)对于map.put("KEY","FINALLY"),形参和实参的内容一致,且因为map为引用类型,所以形参和实参存储的为地址。此时调用形参改变自身内容的方法将会影响到该地址指向的对象的内容。所以,map中"KEY"对应的值改变了。
测试用例1还可以说明:返回语句是try中的return语句而不是finally外面的return 2000;这句。
4、try块里的return语句在异常的情况下不会被执行,这样具体返回哪个看情况。
 package com.meng.javalanguage.finallytest;
 public class FinallyTest4 {
     public static void main(String[] args) {
         System.out.println(test4());
     }
     public static int test4() {
         int b = 20;
         try {
             System.out.println("try block");
             b = b / 0;
             return b += 80;
         } catch(Exception e) {
             b += 15;
             System.out.println("catch block");
         }
         finally {
             System.out.println("finally block");
             if(b > 25) {
                 System.out.println("b > 25,b = " + b);
             }
             b += 50;
         }
         return b;
     }
 }
运行结果是:

这里因为在return之前发生了除0异常,所以try中的return不会被执行到,而是接着执行捕获异常的catch语句和最终的finally语句,此时两者对b的修改都影响了最终的返回值,这时return b;就返回了最后对b进行修改后的值。当然如果你这里将return b改为return 300什么的,最后返回的就是300,这毋容置疑。
这里大家可能又有疑问:如果catch中有return语句呢?当然只有在异常的情况下才有可能会执行,那么是在finally之前就返回吗?看下面
5、当发生异常后,catch中的return执行情况与未发生异常时try中return的执行情况完全一样。
 package com.meng.javalanguage.finallytest;
 public class FinallyTest5 {
     public static void main(String[] args) {
         System.out.println(test5());
     }
     public static int test5() {
         int b = 20;
         try {
             System.out.println("try block");
             b = b / 0;
             return b += 80;
         }catch(Exception e) {
             System.out.println("catch block");
             return b += 15;
         }
         finally {
             System.out.println("finally block");
             if(b > 25) {
                 System.out.println("b > 25,b = " + b);
             }
             b += 50;
         }
 //        return b;
     }
 }
运行结果是:

说明了发生异常后,catch中的return语句先执行,确定了返回值后再去执行finally块,执行完了catch再返回,finally里对b的改变对返回值无影响,原因同前面 一样,也就是说情况与try中的return语句执行完全一样。
最后总结:finally块的语句在try或catch中的return语句执行之后返回之前执行,且finally里的修改语句可能影响也可能不影响try或catch块中return已经确定的返回值,若finally里也有return语句则覆盖try或catch中的return语句直接返回。
转载自《Java finally语句到底是在return之前还是之后执行?》
【转】Java finally语句到底是在return之前还是之后执行?的更多相关文章
- Java finally语句到底是在return之前还是之后执行(JVM字节码分析及内部体系结构)?
		之前看了一篇关于"Java finally语句到底是在return之前还是之后执行?"这样的博客,看到兴致处,突然博客里的一个测试用例让我产生了疑惑. 测试用例如下: public ... 
- Java finally语句到底是在return之前还是之后执行
		看过网上关于Java中异常捕获机制try-catch-finally块中的finally语句是不是一定会被执行的讨论也有很多. 首先明确一点,下面两种情况finally肯定是不执行的: 1). ret ... 
- Java finally语句到底是在return之前还是之后执行?
		网上有很多人探讨Java中异常捕获机制try...catch...finally块中的finally语句是不是一定会被执行?很多人都说不是,当然他们的回答是正确的,经过我试验,至少有两种情况下fina ... 
- 深入理解finally关键字,Finally到底是在return前面执行还是在return后面执行
		一:2种finally不会执行的情况 a.在try语句之前就return了 b.try语句中有System.exit();语句 二:finally语句在return执行之后,return返回之前执行 ... 
- java中return与finally的执行顺序
		可不能小看这个简单的 finally,看似简单的问题背后,却隐藏了无数的玄机.接下来我就带您一步一步的揭开这个 finally 的神秘面纱. 问题分析 首先来问大家一个问题:finally 语句块一定 ... 
- java break语句的三种用法
		1.用于switch语句当中,用于终止语句 2.用于跳出循环,此为不带标签的break语句,相当与goto的作用 e.g while(i<j&&h<k){ if(h< ... 
- java之trycatchfinally代码块与return,throw的执行顺序的探索
		时光荏苒,转眼间毕业都半年了,java编程也五个月了.写代码的过程中,会经常遇到解决代码抛异常的情况.平时只注重完成功能,也没太注意try_catch_finally的内在执行顺序,只知道表面的现象: ... 
- java参数传递时到底是值传递还是引用传递
		java参数传递时到底是值传递还是引用传递(baidu搜集) 问”,很多人的BLOG里都引用这些面试题,最近因为工作内容比较枯燥,也来看看这些试题以调节一下口味,其中有一道题让我很费解. 原题是:当一 ... 
- 【Demo 0002】Java基础-语句
		本章学习要点: 1. 掌握Java关健语句使用方法; 2. 理解与语句相关的关键字用法; 一.Java 关键语句 Java语句以及关联关键字与C完全相 ... 
随机推荐
- MVC项目报错  ”基础提供程序在 Open 上失败”
			问题: 今天将一个.net mvc项目拷贝到另一台电脑上,重新部署的时候,出现以下异常信息: “System.Data.Entity.Core.EntityCommandExecutionExcept ... 
- lnk快捷方式变记事本打开还原,桌面图标变lnk还原方法
			今天天碰到一坑爹问题,打开一个.ini文件自动设置用记事本打开,所有快捷方式都变成记事本打开了,如下图,网上找了一些方法. windows中LNK文件打开方式恢复 相信有些用户曾试过错误地把LNK文件 ... 
- Django之组件--中间件
			中间件 中间件是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影响到性能 自定义中间 ... 
- 在Java中如何高效的判断数组中是否包含某个元素
			原文出处: hollischuang(@Hollis_Chuang) 如何检查一个数组(无序)是否包含一个特定的值?这是一个在Java中经常用到的并且非常有用的操作.同时,这个问题在Stack Ove ... 
- 转--select/poll/epoll到底是什么一回事
			面试题:说说select/poll/epoll的区别. 这是面试后台开发时的高频面试题,属于网络编程和IO那一块的知识.Android里面的Handler消息处理机制的底层实现就用到了epoll. 为 ... 
- JAVA正确地自定义比较对象---如何重写equals方法和hashCode方法
			在实际应用中经常会比较两个对象是否相等,比如下面的Address类,它有两个属性:String province 和 String city. public class Address { priva ... 
- vue2.0页面缓存和不缓存的方法
			// 模板中: <div class="home"> <keep-alive> <router-view v-if="$route.meta ... 
- 【LeetCode】335. Self Crossing(python)
			Problem:You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metr ... 
- dll和lib的关系(转)
			转自http://blog.163.com/zhengjiu_520/blog/static/3559830620093583438464/ 前面有一章说编译与链接的,说得很简略,其实应该放到这一章一 ... 
- oracle 对对表匹配的进行修改匹配不上的可以进行新增 (MERGE  INTO)
			MERGE语句是Oracle9i新增的语法,用来合并UPDATE和INSERT语句. 通过MERGE语句,根据一张表或子查询的连接条件对另外一张表进行查询, 连接条件匹配上的进行UPDATE,无法匹配 ... 
