有关于异常捕获点滴,plus我也揭揭apache-common ExceptionUtils的短

简介: 本文通过示例展示了Java编程中异常处理的几种不当做法,包括无意义地捕获并重新抛出异常、改变异常堆栈信息以及私自“吞噬”异常等,并指出了这些做法可能带来的问题,如增加排障难度等。同时,文章推荐了在捕获异常后打印错误日志的良好习惯,并介绍了如何使用`try...finally`结构进行资源管理和程序状态记录。此外,还特别提到了Apache Commons Lang库中的`ExceptionUtils`工具类在记录异常堆栈信息方面的应用价值,但也对其某些行为提出了疑问,鼓励读者深入探究。

先如下代码:

1    @Test

2     public void testException1() {

3         System.out.println("begin...");

4         int[] arr = new int[]{1};

5         System.out.println(arr[1]);

6     }

如下是运行结果,异常是从第5行抛出来的,控制台里显示的异常堆栈信息也是始于第5行。

java.lang.ArrayIndexOutOfBoundsException: 1
    at com.mytest.testException1(MyExceptionTest.java:5)


我们在写程序时往往要捕获异常。如下是画蛇添足型:

1    @Test

2     public void testException() {

3         try {

4             System.out.println("begin...");

5             int[] arr = new int[]{1};

6             System.out.println(arr[1]);

7         } catch (Exception ex) {

8             throw ex;

9        }

10     }

很明显,捕获了异常,却只是原样throw出去,没任何意义!


如下处理方式也不可取:

1    @Test

2     public void testException() {

3         try {

4             System.out.println("begin...");

5             int[] arr = new int[]{1};

6             System.out.println(arr[1]);

7         } catch (Exception ex) {

8             throw new MyException( ex.getMessage() );

9        }

10     }

 

异常的堆栈始于抛出异常的代码行。catch里经过这样中转后,导致堆栈信息的显示的行号不再是6,而是8。尤其当代码逻辑复杂时,这样做无疑增加了排障的难度。

当然,我们有时要在系统里通过自定义异常类型,来实现我们所需的逻辑控制(自定义异常是个好东西哦,《代码整洁之道》一书中多次提到使用异常来替代错误码)。如果真要通过MyExecption中转出去,可在throw之前将完整的异常信息记录到日志文件里。

catch里捕获到Exception后,先打印error log再做后续处理,会是个好习惯。


私自吞异常是要犯法的哦~~

类似如下代码是不是很熟悉?哈哈,去翻翻自己写的代码吧~

1     public int myBiz() {

2         int result;

3         try {

4             System.out.println("begin...");

5             int[] arr = new int[]{1};

6             result = arr[1];

7             return result;

8         } catch (Exception e) {

9             return 0;

10        }

11     }

 

有时,我们要借助try...finally

finally里的代码会在try子句或catch子句执行完成后执行。借助try...finally,我们可以设置日志埋点,比如:记录程序耗时,记录程序完结标记。也可以用来释放资源,例如:关闭IO、释放流。

1     public void testTryFinally() {

2         try {

3             System.out.println("begin...");

4             int[] arr = new int[]{1};

5             System.out.println(arr[1]);

6         }finally {

7             System.out.println("over");

8        }

9     }

 

利用ExceptionUtils记录异常

当程序运行过程中出现异常时,将异常的详细信息打印到日志文件是必不可少的,这将有助于我们排障。

.net程序员都知道,要打印出来一个异常的详细信息,直接ex.ToString()就可以了。

如果在java里,你还这样,那就out了。查看一下Exception的基类——Throwable的toString()方法,可知,ex.toString()返回的是异常类型和message。

这时,要打印完整的异常信息,apache commons-lang3包里的ExceptionUtils工具类可要派上用场了。 没错,用ExceptionUtils#getStackTrace(final Throwable throwable)

揭短ExceptionUtils

有些异常并没有root cause的,此时,调用ExceptionUtils的getRootCause(final Throwable throwable)返回值是null,而你调用其getRootCauseMessage(final Throwable th)时,反而有返回值。 查看getRootCauseMessage的代码实现,发现它做了二元判断,如果root cause是null,它就去取th本身的message。 前者返回null,后者有返回值,自我赶脚有些费解!what about you?

//public class ExceptionUtils {
public static Throwable getRootCause(final Throwable throwable) {
    final List<Throwable> list = getThrowableList(throwable);
    return list.size() < 2 ? null : (Throwable)list.get(list.size() - 1);
}
public static String getRootCauseMessage(final Throwable th) {
    Throwable root = ExceptionUtils.getRootCause(th);
    root = root == null ? th : root;
    return getMessage(root);
}

 

目录
相关文章
打印全部异常堆栈、ExceptionUtils.getFullStackTrace这样最快
打印全部异常堆栈、ExceptionUtils.getFullStackTrace这样最快
505 0
|
2月前
|
人工智能 前端开发 JavaScript
SpringBoot实现网页消息推送的5种方法
本文详细介绍了在SpringBoot中实现网页消息推送的几种主流方案,包括短轮询、长轮询、SSE(Server-Sent Events)、WebSocket以及STOMP。每种方案各有优缺点,适用于不同的场景需求。短轮询简单易实现但效率低;长轮询提升了实时性但仍有限制;SSE适合单向通信且轻量高效;WebSocket支持全双工通信,适合高实时性要求的场景;STOMP基于WebSocket,提供更高级的消息传递功能。通过对比分析,开发者可根据业务需求、性能要求及浏览器兼容性选择最适合的技术方案,同时可结合多种技术实现优雅降级,优化用户体验。
304 57
|
11月前
|
安全 机器人 测试技术
宇树Unitree Z1机械臂使用教程
本文是宇树Unitree Z1机械臂的使用教程,包括建立机械臂通信、基本运行demo、ROS Gazebo仿真demo、键盘控制demo、手柄控制demo、moveit真实机械臂demo以及其他高级控制demo的详细步骤和注意事项。教程涵盖了软件安装、环境配置、代码下载、编译运行等内容,并提供了机械臂操作的实用技巧。
1002 1
|
11月前
|
SQL 分布式计算 DataWorks
利用DataWorks构建高效数据管道
【8月更文第25天】本文将详细介绍如何使用阿里云 DataWorks 的数据集成服务来高效地收集、清洗、转换和加载数据。我们将通过实际的代码示例和最佳实践来展示如何快速构建 ETL 流程,并确保数据管道的稳定性和可靠性。
367 56
|
10月前
6-14|gitlab的runner的流水线怎么看
6-14|gitlab的runner的流水线怎么看
|
11月前
|
虚拟化
如何为VM虚拟机添加D盘
这篇文章介绍了如何在VMware虚拟机中将E盘修改为D盘,并提供了详细的操作步骤,包括在计算机管理中更改驱动器号和路径,以及初始化和格式化新磁盘的指导。
如何为VM虚拟机添加D盘
|
11月前
【Python-Numpy】numpy.expand_dims()的解析与使用
np.expand_dims()函数的作用,它用于在指定位置插入新轴,扩展数组的维度。
179 2
|
机器学习/深度学习 自然语言处理
扩散模型在文本生成领域的应用
扩散模型在文本生成领域的应用
410 0
|
NoSQL 编译器 C语言
Visual Studio Code (VS Code) – C++ 入门
基于 Visual Studio Code 官方文档的全面的、具体的入门级教程
512 1
Visual Studio Code (VS Code) – C++ 入门
|
网络协议 中间件 测试技术
新一代通信协议—— RSocket
新一代通信协议—— RSocket
581 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等