Java异常处理中一些隐蔽问题的分析总结

背景:
不论是在近期的程序开发工作中,还是在过往的开发经历中,java异常处理的代码总是能经常遇到,有些异常处理的不太合适,会引起业务上不好的体验、bug,下面将总结几个问题场景以及对应解决思路。

内容:
1.当捕获到一个异常时,要不要吃掉、吞掉异常?
所谓吞掉异常,是指处理后不再将异常上抛,比如捕获异常后打印日志、发通知后不再上抛;捕获异常后返回null值给上层等。
要不要吞掉异常?这需要看异常的类型、是否涉及事务、当前具体的需求场景等情况。
1.1我们查看spring事务部分的源码:
在这里插入图片描述
可以看到,如果设置了事务属性并且当前异常满足rollbackon指定的异常,则会回滚当前事务,否则提交。因此,如果捕获异常后没有再次抛出或没有手动回滚异常,那么事务将被提交,需要注意这一点。

1.2再看另一个场景:在接口中简单输出异常日志并返回null
在这里插入图片描述
试想如果调用方拿到返回值对象未做判空处理直接使用该对象,很容易就报NullPointException(NPE)异常。此外异常中包含的信息无法传给上层提示到前端,用户会很困惑,增加线上咨询量。
因此,尽量避免接口返回null,与调用方约定好始终返回一个非空对象,该对象中含有调用结果是否成功的标记,以及返回的数据。
实际项目中在对异常进行处理时,应适当考虑在对象中返回业务信息,经过控制层封装转换后返回前台,给用户一个更好的提示体验。同时在后台记录日志,便于开发人员排查问题。

2.循环中的异常处理
2.1普通循环中的异常处理对代码执行的影响
代码1:
在这里插入图片描述
代码2:
在这里插入图片描述

代码1中,当发生远程调用异常时,循环直接中断,后续不再执行。代码2中,当发生远程调用异常时,本次循环调用的后续数据处理不再执行,后续循环将继续执行。选择上述哪种方式,需要结合具体的业务来判断。

2.2结合线程池的循环中的异常处理对代码的影响
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
printList1当执行到ab时会抛出异常,此时线程池中线程销毁,当执行到abc时,线程池会创建新线程来执行,因此可以继续执行后续循环。而printList2中,for循环在一个线程内,当执行到ab时,线程销毁,无法执行后续循环内容。如果要在printList2基础上使得循环继续执行,作如下修改:
在这里插入图片描述
实际开发过程中,这种问题比较隐蔽,需要多加留意。

3.要理解好java中的异常体系,如下图。
在这里插入图片描述
实际开发中要区分好受检异常与非受检异常,通常开发中自定义的业务异常属于非受检异常,且定义为RuntimeException的子类。很多项目中BussinessException异常类正是这么设计的。

猜你喜欢

转载自blog.csdn.net/csdnklsdm/article/details/121213561