网站首页 > java教程 正文
前言
Java中一个大家熟知的知识点就是异常捕获,try...catch...finally组合,但是很多人不知道这里面有一个关于Java的缺陷,或者说是异常实现的一点不足之处。
我这边就通过一个很简单的实验给大家演示下效果玩玩儿,希望大家能觉得有趣。
模拟
1、自定义异常
这里,我们首先写一个自定义业务异常,专门用来抛出。
/**
* <p>
* 自定义业务异常
* </p>
*
* @author 程序员济癫,公众号:【Java分享客栈】
* @since 2022/12/6 19:20
*/
public class BusinessException extends RuntimeException {
public BusinessException() {
super();
}
public BusinessException(String errMsg) {
super(errMsg);
}
public BusinessException(String errMsg, Throwable throwable) {
super(errMsg, throwable);
}
}
2、模拟异常
然后,我们写个测试方法来捕获并抛出空指针异常。
/**
* <p>
* 测试异常缺陷
* </p>
*
* @author 程序员济癫,公众号:【Java分享客栈】
* @since 2022/12/6 19:22
*/
@Slf4j
public class ExceptionTest {
public static void main(String[] args) {
try {
UserInfo userInfo = null;
System.err.println(userInfo.getName());
} catch (Exception ex) {
throw new BusinessException("捕获try的异常: " + ex.getMessage());
}
}
}
看下效果,OK没问题。
接下来,我们加上finally看看。
/**
* <p>
* 测试异常缺陷
* </p>
*
* @author 程序员济癫,公众号:【Java分享客栈】
* @since 2022/12/6 19:22
*/
@Slf4j
public class ExceptionTest {
public static void main(String[] args) {
try {
UserInfo userInfo = null;
System.err.println(userInfo.getName());
} catch (Exception ex) {
throw new BusinessException("捕获try的异常: " + ex.getMessage());
} finally {
System.err.println("----------finally最终执行---------");
}
}
}
看下效果,OK也没问题。
接下来我们这么做,在finally中抛出一个异常。
/**
* <p>
* 测试异常缺陷
* </p>
*
* @author 程序员济癫,公众号:【Java分享客栈】
* @since 2022/12/6 19:22
*/
@Slf4j
public class ExceptionTest {
public static void main(String[] args) {
try {
UserInfo userInfo = null;
System.err.println(userInfo.getName());
} catch (Exception ex) {
throw new BusinessException("捕获try的异常: " + ex.getMessage());
} finally {
System.err.println("----------finally最终执行---------");
throw new BusinessException("覆盖catch的异常");
}
}
}
看下效果,发现catch的异常竟然被覆盖了。
虽然这种场景很特殊,但这其实就是Java在异常实现上美中不足的地方,因为异常是作为程序出错的标志绝对不应忽略,可是这种场景下异常的的确确丢失了。
接下来,我们再测试一种情况,在finally中使用return,看看会发生什么。
/**
* <p>
* 测试异常缺陷
* </p>
*
* @author 程序员济癫,公众号:【Java分享客栈】
* @since 2022/12/6 19:22
*/
@Slf4j
public class ExceptionTest {
public static void main(String[] args) {
try {
UserInfo userInfo = null;
System.err.println(userInfo.getName());
} catch (Exception ex) {
throw new BusinessException("捕获try的异常: " + ex.getMessage());
} finally {
System.err.println("----------finally最终执行---------");
return;
}
}
}
看看效果,发现catch中捕获的异常干脆直接没了,仿佛从没来过。
最后,我们再演示一种你可能工作中干过或者见过的莫名其妙的事情。
我们修改一下这个测试方法,看代码。
/**
* <p>
* 测试异常缺陷
* </p>
*
* @author 程序员济癫,公众号:【Java分享客栈】
* @since 2022/12/6 19:22
*/
@Slf4j
public class ExceptionTest {
public static void main(String[] args) {
try {
// 调用其他类的查询方法
queryData();
} catch (Exception ex) {
// 捕获这个查询方法抛出的异常
throw new BusinessException(ex.getMessage());
}
}
private static void queryData() {
try {
// 这个方法刚好你也try..catch了,并且在finally中做了一些末尾必须执行的业务逻辑处理。
UserInfo userInfo = null;
System.err.println(userInfo.getName());
} finally {
doSomething();
}
}
private static void doSomething() {
// 业务处理过程中你同样习惯性地抛出了某个业务异常
System.err.println("--------处理末尾业务--------");
throw new BusinessException("处理末尾业务抛出逻辑异常");
}
}
简单描述一下,你调用其他类的一个查询方法,那个方法可能习惯性的try..catch..finally了,而finally中还做了一些末尾必须要执行的操作,这个业务逻辑处理可能有几十行,你很可能又习惯性的做了一些判断以及异常的抛出。
别不相信,当一个项目进入中期甚至赶进度的时候,方法套方法,不少人已经在机械的茫然的写代码,也可能是在别人的基础上改代码,你很可能不会太仔细地一行一行去看那些代码里究竟有什么,恰巧测试的时候也没出什么大问题。
那么结果可能就是下面这样,你会发现自己一开始特意抛出的那个捕获该查询方法异常的玩意儿没一点效果,也不知道去哪儿了,怎么找也找不到,不知从哪儿冒出来下面这个莫名其妙的异常,后来想不到也就算了。
原因
这其实就是Java异常实现的一个不足,异常是程序出错的标志,怎么都不应该被忽略掉,更不用说是finally这种常用的行为,直接或间接地造成了异常的丢失。
《Thinking In Java》的作者有明确指出这个异常,认为这是相当严重的缺陷,是一个可能造成异常完全丢失的缺陷,而且是以一种更微妙、更难以察觉的方式在进行。
而C++就处理的很好,会将这种在第一个异常被处理之前抛出第二个异常的情况视为严重的编程错误。
总结
知道了这个缺陷后,其实就很好避免了。
1、避免在finally中抛出异常;
2、避免在finally中使用return;
3、catch中一定要养成log.error记录异常日志的好习惯,因为log是一定会记录下来的,至少不会让你毫无线索。
结尾再演示下加了日志的效果,只要是catch我都加上日志,那么一定不会错过。
END
私信回复【资料】有更多惊喜哦
猜你喜欢
- 2024-11-06 Java核心知识3:异常机制详解(java的三种核心机制是什么)
- 2024-11-06 【Spring系列】05 自定义异常以及全局异常处理器 #java
- 2024-11-06 3种Sentinel自定义异常,你用过几种?
- 2024-11-06 关于Java Exception异常的深入用法及实例
- 2024-11-06 Java-throw异常详解以及过程(java throw exception)
- 2024-11-06 《JAVA编程思想》5分钟速成:第12章(异常)
- 2024-11-06 面试官:java开发中异常怎么定义好 程序员:不知道
- 2024-11-06 「译」11条Java异常处理的最佳实践
- 2024-11-06 Java入门教程十一(异常处理)(java异常处理的三种方法)
- 2024-11-06 Java,你管这叫异常?(java异常是什么意思)
你 发表评论:
欢迎- 05-16SpringBoot整合Redis实现常用功能
- 05-16基于Redis实现简单的延时消息队列
- 05-16安装Redis
- 05-16Spring系列之Redis的两种集成方式
- 05-16Django连接Redis集群问题排查思路和总结
- 05-16只需5分钟,完成Redis所有命令操作~
- 05-16熟练使用 Redis 的 5 大数据结构:Java 实战教程
- 05-16Redis 常见业务场景及实例(Java)
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)