有关于异常捕获点滴,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这样最快
676 0
|
SQL Java 测试技术
在Spring boot中 使用JWT和过滤器实现登录认证
在Spring boot中 使用JWT和过滤器实现登录认证
1106 0
|
API 云栖大会
通义千问升级旗舰模型Qwen-Max,性能接近GPT-4o
通义旗舰模型Qwen-Max全方位升级,性能接近GPT-4o
9644 12
|
缓存 安全 Java
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
7323 14
Spring Boot 3 集成 Spring Security + JWT
|
监控 安全 持续交付
深入探讨 Webhook 的本质、工作原理以及其在不同领域的应用,帮助你更好地理解和运用这一技术
Webhook是一种在特定事件发生时,由服务器主动向客户端发送通知的机制,实现数据的实时、高效传递。本文介绍Webhook的基本概念、工作原理、应用场景及设置使用方法,探讨其优势与挑战,帮助读者更好地理解和应用这一技术。
2456 8
|
开发框架 IDE Java
java制作游戏,如何使用libgdx,入门级别教学
本文是一篇入门级教程,介绍了如何使用libgdx游戏开发框架创建一个简单的游戏项目,包括访问libgdx官网、设置项目、下载项目生成工具,并在IDE中运行生成的项目。
921 1
java制作游戏,如何使用libgdx,入门级别教学
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第19天】本文介绍了Java编程中重要的数据结构——Map,通过问答形式讲解了Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的使用和性能优化技巧,适合初学者和进阶者学习。
749 4
|
Linux C语言
成功解决 在Linux CentOS 7 中安装gcc
这篇文章介绍了如何在Linux CentOS 7系统中安装gcc (g++) 8工具集。由于CentOS 7默认的gcc版本是4.8,而这个版本与Qt 5.14、Qt 5.15或更高版本不兼容,可能会导致编译时出现系统头文件错误。文章中提到,即使在项目配置中添加了`CONFIG+=c++11`,如果仍然报错,那么很可能是gcc版本的问题。为了解决这个问题,文章提供了使用CentOS的Software Collections (scl)来安装更新版本的gcc的步骤。
成功解决 在Linux CentOS 7 中安装gcc
|
架构师 Java 数据库连接
成功解决:com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl.
这篇文章提供了解决Spring整合MyBatis时报错的配置方法,包括使用Spring的上下文属性占位符加载数据库配置文件`db.properties`,并在Spring配置文件中声明并配置数据源`DruidDataSource`。

热门文章

最新文章