【转】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完全相 ...
随机推荐
- [JVM-3]Java垃圾回收(GC)机制和垃圾收集器选择
哪些内存需要回收? 1.引用计数法 这个算法的实现是,给对象中添加一个引用计数器,每当一个地方引用这个对象时,计数器值+1:当引用失效时,计数器值-1.任何时刻计数值为0的对象就是不可能再被使用的.这 ...
- 【1】【leetcode-115】 不同的子序列 distinct-subsequences
不同的子序列 distinct-subsequences(hard) (忘了,典型) 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删 ...
- Leetcode 136 Single Number 仅出现一次的数字
原题地址https://leetcode.com/problems/single-number/ 题目描述Given an array of integers, every element appea ...
- java中变量关系
- 上传文件服务与web服务分离
业务场景:1. 后端服务为java web应用,使用tomcat容器,多实例集群化部署.2. 前端使用nginx作为后端应用的反向代理. 业务需求:现在需要在java web应用端上传文件,同时还要能 ...
- 细说shiro之一:shiro简介
官网:https://shiro.apache.org/ 一. Shiro是什么Shiro是一个Java平台的开源权限框架,用于认证和访问授权.具体来说,满足对如下元素的支持: 用户,角色,权限(仅仅 ...
- 利用 yEd 软件做元数据管理
利用 yEd 软件做元数据管理 yEd Diagram editor 是我常用的 flow chart 制图工具, 另外我也用它画 ER 和 use case 图. 总结一下我喜欢 yEd 的原因:1 ...
- 完全使用UDP登录Linux
===============Mosh 登录器========================================= == 针对TCP被某些防火墙阻断的Linux机器, 该程序可以让你不使 ...
- SQL Server进阶(十一)存储过程
存储过程和函数的区别 存储过程是第一次编译之后就会被存储的下来的预编译对象,之后无论何时调用它都会去执行已经编译好的代码.而函数每次执行都需要编译一次.总结下来有下面几个区别: 基本不同: 函数必须有 ...
- Sqlserver脚本创建登录名密码
use table1 GO ', default_database=table1; GO create user abc for login abc with default_schema=dbo; ...