当前位置:网站首页>究极异常处理逻辑——多层次异常的处理顺序
究极异常处理逻辑——多层次异常的处理顺序
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 {}
中的逻辑均会执行。
六、写在后面
欢迎关注,会经常记录一些学习思考笔记。如有错误与补充,感谢您的指出。
欢迎随时留言讨论,与君共勉,知无不答!
边栏推荐
猜你喜欢
关于我用iVX沉浸式体验了一把0代码项目创建
LeetCode·76.最小覆盖子串·滑动窗口
Flink学习9:配置idea开发flink-Scala程序环境
2022年PMP考试应该注意些什么?
默认参数的代码实现及日期的注入与显示
Pytest学习笔记
Five speakers: seventy genius_platform software platform development 】 【 turn YUY2 RGB24 implementation source code
navicat premium 15 下载安装详细教程
【genius_platform软件平台开发】第七十五讲:YUY2转RGB24实现源码
[C Language Brush Questions] Three Questions for Getting Started with Pointers | String Length, String Copy, Two Number Swap
随机推荐
Mysql——分组统计
电烙铁的基础知识
用函数递归的方法解决汉诺塔问题
Nacos面试题
小程序毕设作品之微信体育馆预约小程序毕业设计成品(7)中期检查报告
恒驰5真的没大卖
golang源码分析(3):thrift
常用软件静默安装参数
ES: WeakSet
红蓝对抗经验分享:CS免杀姿势
腾讯架构师是如何解释:Redis高性能通信的原理(精华版)
Gartner released, annual Challenger!
golang源码分析(2):Golang context 包
MySQL常见函数
Oracle分析归档日志内容时,发现很多null?
暴跌99.7%后,谁还在买卖「二舅币」?
金仓数据库KingbaseES安全指南--6.12. BSD身份验证
持续集成(四)Jenkins配置报警机制
「全球数字经济大会」登陆 N 世界,融云提供通信云服务支持
动力电池扩产潮,宁德时代遭围剿