当前位置:网站首页>究极异常处理逻辑——多层次异常的处理顺序
究极异常处理逻辑——多层次异常的处理顺序
2022-08-02 17:09:00 【Java咩】
目录
多层次异常的处理顺序
之前在牛客做笔试题的时候,由于遇到了一道多层次异常相关的题,所以对多层次异常的处理顺序格外留心,在上周工作增加并发锁的时候,由于是锁的嵌套,也就是 异常处理 嵌套 异常处理。于是决定深究一下多层次异常处理的优先级。
零、代码执行环境
IDEA版本:2022.1.3
JDK版本:jdk1.8.0_181
一、try、catch 和 finally 中 return 的优先级问题
首先,我们先来探究产生是否产出异常对 try、catch 和 finally 中 return 的优先级 的影响
测试代码:
public class Test {
public static void main(String[] args) {
System.out.println("产生异常时:a = " + test1());
System.out.println("未产生异常时:a = " + test2());
public static String test1() {
String res = "初始内容 ";
try {
int a = 1 / 0;
return res + " + try 返回了";
} catch (Exception e) {
res += " + catch 执行了";
return res + " + catch 返回了";
} finally {
res += " + finally 执行了";
return res + " + finally 返回了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
public static String test2() {
String res = "初始内容 ";
try {
// int a = 1 / 0;
return res + " + try 返回了";
} catch (Exception e) {
res += " + catch 执行了";
return res + " + catch 返回了";
} finally {
res += " + finally 执行了";
return res + " + finally 返回了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
}
运行结果:
产生异常时:初始内容 + catch 执行了 + finally 执行了 + finally 返回了
不产生异常时:初始内容 + finally 执行了 + finally 返回了
结果分析:
通过结果可以看出,无论是否产生异常,一旦 finally {} 语句块中含有 retuan 那么都会执行 finally {} 语句中的 retuan 语句。
二、try 和 catch 中 return 的优先级问题
测试代码:
public static void main(String[] args) {
System.out.println("产生异常时:" + test1());
System.out.println("不产生异常时:" + test2());
}
public static String test1() {
String res = "初始内容 ";
try {
// int a = 1 / 0;
return res + " + try 返回了";
} catch (Exception e) {
res += " + catch 执行了";
return res + " + catch 返回了";
} finally {
System.out.println("finally 执行了");
res += " + finally 执行了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
public static String test2() {
String res = "初始内容 ";
try {
int a = 1 / 0;
return res + " + try 返回了";
} catch (Exception e) {
res += " + catch 执行了";
return res + " + catch 返回了";
} finally {
System.out.println("finally 执行了");
res += " + finally 执行了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
}
运行结果:
finally 执行了
不产生异常时:初始内容 + try 返回了
finally 执行了
产生异常时:初始内容 + catch 执行了 + catch 返回了
结果分析:
不产生异常时:执行 try {} 语句中的 retuan 语句。
产生异常时:执行 catch {} 语句中的 retuan 语句
值得注意的是: finally {} 语句中的语句也执行了,但是对于字符串 res 的操作没有生效。
如果是返回基本类型的值,那么在缓存时也是缓存值本身,所以后面在finally块中重新赋值时,方法返回的值不会受finally块中重新赋值的影响;
如果返回的是引用类型的值,那么在缓存时,缓存的是引用类型对象的引用,所以虽然后面在finally块中重新赋值时(重新指向另一个对象),方法返回的值不会受到影响,但是如果是修改对象的属性,那么会影响到返回的值。
参考链接:finally语句中对变量进行赋值的问题
三、finally 中 return 对 catch 中异常的影响
public class Test {
public static void main(String[] args) {
System.out.println("finally 有 return 时:" + test1());
System.out.println("finally 无 return 时:" + test2());
}
public static String test1() {
String res = "初始内容 ";
try {
int a = 1 / 0;
return res;
} catch (Exception e) {
int a = 1 / 0;
res += " + catch 执行了";
return res;
} finally {
res += " + finally 执行了";
return res ;
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
public static String test2() {
String res = "初始内容 ";
try {
int a = 1 / 0;
return res;
} catch (Exception e) {
int a = 1 / 0;
res += " + catch 执行了";
return res;
} finally {
res += " + finally 执行了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
}
运行结果:
finally 有 return 时:初始内容 + finally 执行了
Exception in thread "main" java.lang.ArithmeticException: / by zero
结果分析:
根据结果可以看出,如果 finally {} 代码块中有 retuan 时, catch {} 中的异常不会被处理。
四、多层次 try 、 catch 和 finally 中 return 的优先级问题
public class Test {
public static void main(String[] args) {
System.out.println("不产生异常时:" + test1());
System.out.println("内部 try 产生异常时:" + test2());
System.out.println("内部 catch 也产生异常时:" + test3());
}
public static String test1() {
String res = "初始内容";
try {
try {
// int a = 1 / 0;
return res;
} catch (Exception e) {
res += " + 内部代码块的 catch 执行了";
return res;
} finally {
res += " + 内部代码块的 finally 执行了";
return res + " + 内部 finally 返回了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
} catch (Exception e) {
res += " + 外部代码块的 catch 执行了";
return res;
} finally {
res += " + 外部代码块的 finally 执行了";
return res + " + 外部 finally 返回了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
public static String test2() {
String res = "初始内容";
try {
try {
int a = 1 / 0;
return res;
} catch (Exception e) {
res += " + 内部代码块的 catch 执行了";
return res;
} finally {
res += " + 内部代码块的 finally 执行了";
return res + " + 内部 finally 返回了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
} catch (Exception e) {
res += " + 外部代码块的 catch 执行了";
return res;
} finally {
res += " + 外部代码块的 finally 执行了";
return res + " + 外部 finally 返回了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
public static String test3() {
String res = "初始内容";
try {
try {
int a = 1 / 0;
return res;
} catch (Exception e) {
int a = 1 / 0;
res += " + 内部代码块的 catch 执行了";
return res;
} finally {
res += " + 内部代码块的 finally 执行了";
return res + " + 内部 finally 返回了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
} catch (Exception e) {
res += " + 外部代码块的 catch 执行了";
return res;
} finally {
res += " + 外部代码块的 finally 执行了";
return res + " + 外部 finally 返回了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
}
运行结果:
不产生异常时:初始内容 + 内部代码块的 finally 执行了 + 外部代码块的 finally 执行了 + 外部 finally 返回了
内部 try 产生异常时:初始内容 + 内部代码块的 catch 执行了 + 内部代码块的 finally 执行了 + 外部代码块的 finally 执行了 + 外部 finally 返回了
内部 catch 也产生异常时:初始内容 + 内部代码块的 finally 执行了 + 外部代码块的 finally 执行了 + 外部 finally 返回了
结果分析:
不产生异常时:正常执行 try {} 中语句,由于外部代码块 finally {} 中有 return 语句,所以只执行外部 finally {} 中的 return 语句。符合我们在 一、try 和 finally 中 return 的优先级问题 中的结论。
try 产生异常时:代码执行 catch {} 部分,由于外部代码块 finally {} 中有 return 语句,所以只执行外部 finally {} 中的 return 语句。符合我们在 一、try 和 finally 中 return 的优先级问题 中的结论。
try 和 catch 同时产生异常时:由于外部代码块 finally {} 中有 return 语句,所以程序不会处理 catch {} 中的异常,故结果和不产生异常时相同。符合我们在 三、finally 中 return 对 catch 中异常的影响 中的结论。
五、多层次 try 和 catch 中 return 的优先级问题
为了验证最后一个结论,我们在 finally {} 中去掉 return 语句,再次执行。
测试代码:
public class Test {
public static void main(String[] args) {
System.out.println("不产生异常时:" + test1());
System.out.println("内部 try 产生异常时:" + test2());
System.out.println("内部 catch 也产生异常时:" + test3());
}
public static String test1() {
String res = "初始内容";
try {
try {
// int a = 1 / 0;
return res + " + 内部代码块的 try 返回";
} catch (Exception e) {
res += " + 内部代码块的 catch 执行了";
return res + " + 内部代码块的 catch 返回";
} finally {
res += " + 内部代码块的 finally 执行了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
} catch (Exception e) {
res += " + 外部代码块的 catch 执行了";
return res + " + 外部代码块的 catch 返回";
} finally {
res += " + 外部代码块的 finally 执行了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
public static String test2() {
String res = "初始内容";
try {
try {
int a = 1 / 0;
return res + " + 内部代码块的 try 返回";
} catch (Exception e) {
res += " + 内部代码块的 catch 执行了";
return res + " + 内部代码块的 catch 返回";
} finally {
res += " + 内部代码块的 finally 执行了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
} catch (Exception e) {
res += " + 外部代码块的 catch 执行了";
return res + " + 外部代码块的 catch 返回";
} finally {
res += " + 外部代码块的 finally 执行了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
public static String test3() {
String res = "初始内容";
try {
try {
int a = 1 / 0;
return res + " + 内部代码块的 try 返回";
} catch (Exception e) {
int a = 1 / 0;
res += " + 内部代码块的 catch 执行了";
return res + " + 内部代码块的 catch 返回";
} finally {
res += " + 内部代码块的 finally 执行了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
} catch (Exception e) {
res += " + 外部代码块的 catch 执行了";
return res + " + 外部代码块的 catch 返回";
} finally {
res += " + 外部代码块的 finally 执行了";
}
// finally 中有 return 的话,这之后的代码由于不会被执行,而产生会编译错误
}
}
运行结果:
不产生异常时:初始内容 + 内部代码块的 try 返回
内部 try 产生异常时:初始内容 + 内部代码块的 catch 执行了 + 内部代码块的 catch 返回
内部 catch 也产生异常时:初始内容 + 内部代码块的 finally 执行了 + 外部代码块的 catch 执行了 + 外部代码块的 catch 返回
结果分析:
不产生异常时:正常执行 try {} 中的 return 。
try 产生异常时:由于 finally {} 中没有 return 语句,所以执行 catch {} 中有 return 语句,但是 finally {} 中的逻辑会执行。
catch 也产生异常时:由于内部 finally {} 中没有 return 语句,所以异常会向外抛出,被外部 catch {} 捕捉到,执行外部 catch {} 中有 return 语句。其中外部 finally {} 中的逻辑均会执行。
六、写在后面
欢迎关注,会经常记录一些学习思考笔记。如有错误与补充,感谢您的指出。
欢迎随时留言讨论,与君共勉,知无不答!
边栏推荐
- 金仓数据库KingbaseES安全指南--6.12. BSD身份验证
- 年轻人接棒大妈,金价跌回“4字头”,七夕迎黄金消费小热潮
- 字节面试官狂问我:你没有高并发、性能调优经验,为什么录取你?
- nacos简单使用
- npm install 编译时报“Cannot read properties of null (reading ‘pickAlgorithm‘)“
- 扎克伯格“喜迎”苹果AR产品,上市两年终迎大幅涨价
- Nacos面试题
- Navicat 连接Oracle时提示oracle library is not loaded的问题解决
- 「全球数字经济大会」登陆 N 世界,融云提供通信云服务支持
- 谁抢走了华大基因的生意?
猜你喜欢

Flink SQL搭建实时数仓DWD层

navicat创建连接 2002-can‘t connect to server on localhost(10061)且mysql服务已启动问题

牛津硕士进碳圈,高瓴红杉经纬一起投了

字节面试官狂问我:你没有高并发、性能调优经验,为什么录取你?

DeepMind 首席科学家 Oriol Vinyals 最新访谈:通用 AI 的未来是强交互式元学习

金仓数据库 OCCI 迁移指南(4. KingbaseES 的 OCCI 迁移指南)

再获权威认证!马上消费安逸花APP通过中国信通院“金融APP人脸识别安全能力评测”

Pytest study notes

Nacos配置中心用法详细介绍

【Redis】连接报错:Could not connect to Redis at 127.0.0.1:6379: Connection refused
随机推荐
持续集成(三)Jenkins新增节点
接入网学习笔记
golang源码分析(7):chan
Oracle 11 g rac finished patch, dbca new patches of SQL database also needs to perform?
JS数组删除其中一个元素
vulnhub W34kn3ss: 1
FPGA 20个例程篇:10.遍历DDR3内存颗粒读写循环校验
nacos集群配置详解
谁抢走了华大基因的生意?
NoSQL之redis缓存雪崩、穿透、击穿概念解决办法
Smart Contract Security - delegatecall (1)
golang源码分析(5):sync.Once
Nacos面试题
Mysql应用安装后找不到my.ini文件
golang源码分析(12)martini源码分析
蔚来杯2022牛客暑期多校训练营5 ABCDFGHK
ES: export 的用法
Several common cross-domain solutions
【genius_platform软件平台开发】第七十五讲:YUY2转RGB24实现源码
德国客户对文档管理系统、工作流自动化软件 DocuWare 的评价