【转】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完全相 ...
随机推荐
- 01--STL泛型编程了解
开始学习侯捷老师的课程了~~ 一:六大组件关系 容器(Container) 算法(Algorithm) 迭代器(Iterator) 仿函数(Function object) 适配器(Adaptor) ...
- 设计模式---数据结构模式之组合模式(Composite)
前提:数据结构模式 常常有一些组建在内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大的破坏组件的复用.这时候,将这些数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无 ...
- rocketmq在linux搭建双master遇到的坑
我的环境 两台阿里云centos7服务器 首先,去官网下载解压包,解压. 然后进入bin目录,需要修改runserver.sh文件和runbroker.sh文件.因为rocketmq默认配置文件需要的 ...
- base64转换成图片
前端代码JS: 前端图片为canvsa绘图转base64格式 function putTextInfo() { var canvasImg = painting.canvas.toDataURL('i ...
- bzoj千题计划317:bzoj4650: [Noi2016]优秀的拆分(后缀数组+差分)
https://www.lydsy.com/JudgeOnline/problem.php?id=4650 如果能够预处理出 suf[i] 以i结尾的形式为AA的子串个数 pre[i] 以i开头的形式 ...
- Part-Three 类与对象
1.时钟类的完整程序 #include<iostream> using namespace std; class Clock{ public : ,,);//设置函数的默认值,注意!在此处 ...
- .net程序集
单程序集 多个.dll或exe 文件 多程序集 单个.dll或exe 文件 单程序集 是一个单一 独立明确定义的包,这个包中包含有程序集清单,CIL和类型元数据 多程序集程序集基本由二进制文件组成(称 ...
- tcp_listen函数
#include <netdb.h> #include <unistd.h> #include <stddef.h> #include <strings.h& ...
- asp.net mvc && asp.net 页面跳转
1.使用传统的Response.Redirect例如string url = "/account/create";Response.Redirect(url); 1.Server. ...
- mysql日期时间函数(常用的)
mysql> SELECT NOW(); #返回(打印)当前日期和时间+---------------------+| NOW() |+---------------------+| 2017 ...