你真的理解Java中的try/catch/finally吗?
看几个例子,回顾一下执行顺序
例子1 无异常,finally中的return会导致提前返回
public static String test() {
try {
System.out.println("try");
return "return in try";
} catch(Exception e) {
System.out.println("catch");
return "return in catch";
} finally {
System.out.println("finally");
return "return in finally";
}
}
调用test()的结果:
try
finally
return in finally
例子2 无异常,try中的return会导致提前返回
public static String test() {
try {
System.out.println("try");
return "return in try";
} catch(Exception e) {
System.out.println("catch");
} finally {
System.out.println("finally");
}
return "return in function";
}
调用test()的结果:
try
finally
return in try
例子3 有异常,finally中的return会导致提前返回
public static String test() {
try {
System.out.println("try");
throw new Exception();
} catch(Exception e) {
System.out.println("catch");
return "return in catch";
} finally {
System.out.println("finally");
return "return in finally";
}
}
调用test()的结果:
try
catch
finally
return in finally
例子4 有异常,catch中的return会导致提前返回
public static String test() {
try {
System.out.println("try");
throw new Exception();
} catch(Exception e) {
System.out.println("catch");
return "return in catch";
} finally {
System.out.println("finally");
}
}
调用test()的结果:
try
catch
finally
return in catch
例子4 有异常,不会提前返回
public static String test() {
try {
System.out.println("try");
throw new Exception();
} catch(Exception e) {
System.out.println("catch");
} finally {
System.out.println("finally");
}
return "return in function";
}
调用test()的结果:
try
catch
finally
return in function
小结
上面这几个例子,大多数人已经非常了解。同时也衍生出一些理论,比如不要在finally中return等,不再赘述。
再看几个例子,返回值是否符合你的预期?
例子1
public static int test() {
try {
return 1;
} finally {
return 2;
}
}
返回值:2
说明:与我们上面的例子一致,finally中的return导致提前返回,try中的return1不会被执行。
附编译后的代码:
public static int test() {
try {
boolean var0 = true;
return 2;
} finally {
;
}
}
可以看到编译器做过优化,同时验证了boolean类型在底层是用int实现的,但注意你在源码中直接给int行赋值true或false是不被允许的。
例子2
public static int test() {
int i;
try {
i = 3;
} finally {
i = 5;
}
return i;
}
返回值:5
说明:执行try中的代码后,再执行finally中的代码,最终i被赋值为5,最后返回
附编译后的代码:
public static int test() {
boolean var0 = true;
byte i;
try {
var0 = true;
} finally {
i = 5;
}
return i;
}
同样可以看出,编译器做了一些优化。
例子3
public static int test() {
int i = 1;
try {
i = 3;
return i;
} finally {
i = 5;
}
}
返回值:3
这个例子稍微有点意思,按我们通常的思维,应该还是返回5,毕竟finally中把i赋值为5了嘛,然后由try中的return返回。然而很不幸,返回值是3。
为什么呢?先看一下编译后的代码:
public static int test() {
boolean var0 = true;
byte var1;
try {
int i = 3;
var1 = i;
} finally {
var0 = true;
}
return var1;
}
我们会发现,finally中的代码块不起作用。不知你是否想起一点:Java中是按值传递的,finally中的i只是一个局部变量,finally块执行完毕后,局部变量便不复存在。
接着看例子:
例子4
public static List test() {
List<Integer> list = new ArrayList<>();
try {
list.add(1);
return list;
} finally {
list.add(2);
}
}
返回:包含1和2两个元素的List对象。
说明:这个例子中,基本类型int被替换为引用类型List,虽然list是按值传递,但它内部的状态可变(体现在这里,就是可以add元素)。扩展:finally只能保证对象本身不可变,但无法保证对象内部状态不可变。
附编译后的代码:
public static List test() {
ArrayList list = new ArrayList();
ArrayList var1;
try {
list.add(1);
var1 = list; // 执行这一步操作后,var1和list指向同一个对象
} finally {
list.add(2);
}
return var1;
}
你现在应该觉得自己理解了,那么再来看两个例子:
例子5
public static int test() {
try {
System.exit(0);
} finally {
return 2;
}
}
该函数没有返回值。原因:jvm提前退出了。
附编译后的代码:
public static int test() {
try {
System.exit(0);
return 2;
} finally {
;
}
}
例子6
public static int test() {
try {
while(true) {
System.out.println("Infinite loop.");
}
} finally {
return 2;
}
}
由于try中的无限循环阻塞,永远执行不到finally中的代码块。
附编译后的代码:
public static int test() {
try {
while(true) {
System.out.println("Infinite loop.");
}
} finally {
;
}
}
小结
为了方便说明,只举了finally代码块的例子,catch代码块是类似的。
总结
执行顺序:
1. try代码块中return前面的部分
2. catch代码块中return前面的部分
3. finally代码块中return前面的部分
4. finally的return 或 catch的return 或 try的return。若前面的return被执行,会导致提前返回,同时后面的return被忽略。
5. 方法的其他部分
变量:
注意Java的按值传递规则
特殊情况:
注意finally不会被执行的情况
参考
你真的理解Java中的try/catch/finally吗?的更多相关文章
- Java内存管理-你真的理解Java中的数据类型吗(十)
勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 作为Java程序员,Java 的数据类型这个是一定要知道的! 但是不管是那种数据类型最 ...
- [转载]java中try 与catch的使用
留着以后看 原文地址:与catch的使用">java中try 与catch的使用作者:碌碌如玉 try{ //代码区 }catch(Exception e){ //异常处理 } 代码区 ...
- 【Java学习笔记之三十三】详解Java中try,catch,finally的用法及分析
这一篇我们将会介绍java中try,catch,finally的用法 以下先给出try,catch用法: try { //需要被检测的异常代码 } catch(Exception e) { //异常处 ...
- 深入理解Java中的不可变对象
深入理解Java中的不可变对象 不可变对象想必大部分朋友都不陌生,大家在平时写代码的过程中100%会使用到不可变对象,比如最常见的String对象.包装器对象等,那么到底为何Java语言要这么设计,真 ...
- 深入理解Java中的IO
深入理解Java中的IO 引言: 对程序语言的设计者来说,创建一个好的输入/输出(I/O)系统是一项艰难的任务 < Thinking in Java > 本文的目录视图如下: ...
- 理解Java中的ThreadLocal
提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...
- JDK学习---深入理解java中的LinkedList
本文参考资料: 1.<大话数据结构> 2.http://blog.csdn.net/jzhf2012/article/details/8540543 3.http://blog.csdn. ...
- 【Java】深入理解Java中的spi机制
深入理解Java中的spi机制 SPI全名为Service Provider Interface是JDK内置的一种服务提供发现机制,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用 ...
- 你真的理解Java 注解吗?
你真的理解Java 注解吗? 1.什么是注解? 官方解释: Java 注解用于为 Java 代码提供元数据.作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的.Java ...
随机推荐
- kubernetes之node隔离与恢复
需求: 在硬件升级, 硬件维护等情况下, 我们需要将某些node隔离, kubectl cordon <node_name> #禁止pod调度到该节点上, 在其上运行的pod并不会自动停止 ...
- Hive正则表达式
正则表达式基本语法 用圆括号将所有选择项括起来,相邻的选择项之间用|分隔.但用圆括号会有一个副作用,使相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种副作用. 其中 ?: 是非捕获元之一,还 ...
- String特性之 “字符串驻留池”
1. 字符串驻留池,就是一块与堆区并行的存放字符串对象的内存区,JVM的驻留池机制规定: 在池中创建一个String对象,第二行会先在池中寻找是否有值与"abc"相同的String ...
- 【NOIP/CSP2019】D1T2 括号树
原题: 因为是NOIP题,所以首先先看特殊数据,前35分是一条长度不超过2000的链,N^2枚举所有子区间暴力check就能拿到分 其次可以思考特殊情况,一条链的情况怎么做 OI系列赛事的特殊性质分很 ...
- cmake学习笔记之add_library、target_link_libraries和link_directories
cmake是Linux(这里默认是Ubuntu系统)下常使用的编译C++的工具,而使用cmake就需要先在CmakeLists.txt文件中对编译规则进行.这里介绍常用的三种指令add_library ...
- web form 服务器控件表单验证
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ValidationDemo ...
- Codeforces Round #588 (Div. 2) D. Marcin and Training Camp(思维)
链接: https://codeforces.com/contest/1230/problem/D 题意: Marcin is a coach in his university. There are ...
- @Transactional(转)
概述@Transactional 是声明式事务管理 编程中使用的注解 添加位置 接口实现类或接口实现方法上,而不是接口类中访问权限:public 的方法才起作用 @Transactional 注解应该 ...
- spring boot 入门 使用spring.profiles.active来分区配置(转)
很多时候,我们项目在开发环境和生成环境的环境配置是不一样的,例如,数据库配置,在开发的时候,我们一般用测试数据库,而在生产环境的时候,我们是用正式的数据,这时候,我们可以利用profile在不同的环境 ...
- curl查看http请求消息的时长
1. -X 指定请求方式GET请求curl -X GET http://www.jackyops.com/search?data=123 # -X GET是可选的 POST请求curl -X POS ...