当前位置:网站首页>究极异常处理逻辑——多层次异常的处理顺序
究极异常处理逻辑——多层次异常的处理顺序
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 {}
中的逻辑均会执行。
六、写在后面
欢迎关注,会经常记录一些学习思考笔记。如有错误与补充,感谢您的指出。
欢迎随时留言讨论,与君共勉,知无不答!
边栏推荐
- 嵌入式Qt-做一个秒表
- Numpy those things
- 启航
- 【电子器件笔记6】三极管(BJT)参数和选型
- 本地MSE播放fragment mp4服务
- When Oracle analyzes the archive log content, it finds many nulls?
- Navicat premium download and install 15 detailed tutorial
- 安全至上:落地DevSecOps最佳实践你不得不知道的工具
- Continuous integration (4) Jenkins configuration alarm mechanism
- What is an APS system?What should I pay attention to when importing APS?Worth watching again and again
猜你喜欢
Wechat Gymnasium Appointment Mini Program Graduation Design Finished Work (5) Task Book
二舅“反转”了?
RAID存储级别分类
Red and blue against experience sharing: CS from kill posture
暴跌99.7%后,谁还在买卖「二舅币」?
土巴兔IPO五次折戟,互联网家装未解“中介”之痛
Oracle 11 g rac finished patch, dbca new patches of SQL database also needs to perform?
Oracle 11g rac打完补丁,dbca新建数据库还需要执行应用补丁的sql吗?
【Redis】连接报错:Could not connect to Redis at 127.0.0.1:6379: Connection refused
文件上传很难搞?10分钟带你学会阿里云OSS对象存储
随机推荐
Oracle 11 g rac finished patch, dbca new patches of SQL database also needs to perform?
金仓数据库KingbaseES安全指南--6.12. BSD身份验证
内网渗透之kerberos认证(三)
Inconsistency between oracle and mysql statement results
Kubernetes:(六)Pod重启策略和状态解释
NoSQL之redis缓存雪崩、穿透、击穿概念解决办法
Wechat Gymnasium Appointment Mini Program Graduation Design Finished Work (5) Task Book
Numpy那些事
Arduino hardware programming introduction to language learning
golang源码分析(12)martini源码分析
npm install报错Fix the upstream dependency conflict, or retry
字节面试官狂问我:你没有高并发、性能调优经验,为什么录取你?
[300+ selected big factory interview questions continue to share] Big data operation and maintenance sharp knife interview questions column (10)
【21天学习挑战赛学习打卡】顺序查找
Kubernetes:(五)Pod进阶(资源限制、健康检查)
navicat creates a connection 2002-can't connect to server on localhost (10061) and the mysql service has started the problem
MySQL常用的日期时间函数
navicat创建连接 2002-can‘t connect to server on localhost(10061)且mysql服务已启动问题
【Redis】连接报错:Could not connect to Redis at 127.0.0.1:6379: Connection refused
Mysql——字符串函数