当前位置:网站首页>究极异常处理逻辑——多层次异常的处理顺序
究极异常处理逻辑——多层次异常的处理顺序
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 {}
中的逻辑均会执行。
六、写在后面
欢迎关注,会经常记录一些学习思考笔记。如有错误与补充,感谢您的指出。
欢迎随时留言讨论,与君共勉,知无不答!
边栏推荐
- Redis的介绍和使用
- What is an APS system?What should I pay attention to when importing APS?Worth watching again and again
- 二舅“反转”了?
- The days of patching are more difficult than the days of writing code
- 土巴兔IPO五次折戟,互联网家装未解“中介”之痛
- Oracle分析归档日志内容时,发现很多null?
- Mini Program Graduation Works WeChat Gymnasium Reservation Mini Program Graduation Design Finished Product (8) Graduation Design Thesis Template
- 内网渗透之kerberos认证(三)
- golang刷leetcode动态规划(8)盈利计划
- Google Earth Engine APP—— 一个不用写代码可以直接下载相应区域的1984-2021年的GIF遥感影像动态图
猜你喜欢
Pytest学习笔记
Mini Program Graduation Works WeChat Gymnasium Reservation Mini Program Graduation Design Finished Product (8) Graduation Design Thesis Template
Five speakers: seventy genius_platform software platform development 】 【 turn YUY2 RGB24 implementation source code
2022年PMP考试应该注意些什么?
mui中使用多级选择器实现省市区联动
MYSQL下载及安装完整教程
SQL语句基础
融云「 IM 进阶实战高手课」系列直播上线
VMware启动报错:另一个程序已锁定文件的一部分,进程无法访问(删除最近的.lck文件夹)
npm install报gyp info it worked if it ends with ok
随机推荐
Kubernetes:(七)优化大法(江湖失传已久的武林秘籍)
2022年PMP考试应该注意些什么?
用函数递归的方法解决汉诺塔问题
npm install报gyp info it worked if it ends with ok
Continuous integration (4) Jenkins configuration alarm mechanism
Inconsistency between oracle and mysql statement results
什么是APS系统?导入APS要注意什么?值得反复观看
erp系统和wms系统有什么区别
golang源码分析(13)gorpc源码分析
边界访问的空间权限
SQL语句基础
Mysql——字符串函数
Nacos配置中心用法详细介绍
npm install 时,卡住不动,五种解决方法
ES: WeakSet
golang源码分析(4):select
nacos简单使用
ffmpeg编译后找不到libx264
图解LeetCode——622. 设计循环队列(难度:中等)
Nacos的基本配置