Spring Boot 使用断言抛出自定义异常,优化异常处理机制

文章目录

    • 什么是断言?
    • 什么是异常?
    • 基于断言实现的异常处理机制
      • 创建自定义异常类
      • 创建全局异常处理器
      • 创建自定义断言类
      • 创建响应码类
      • 创建工具类
      • 测试效果

什么是断言?

实际上,断言(Assertion)是在Java 1.4 版本引入的特性,它为开发人员提供了一种简单的机制来进行代码预期条件的验证和调试。

Java 1.4 版本于2002年发布,它引入了许多新功能和改进,其中之一就是断言。断言的目的是在程序中进行可验证的内部检查,以确保代码的正确性和可靠性。

断言最早是在1989年由美国计算机科学家C.A.R. Hoare提出的概念,称为"断言语句"。然后,在Java 1.4版本中,Sun Microsystems将其引入到Java编程语言中,并添加了关键字assert用于表示断言。

使用assert关键字,开发人员可以在代码中编写断言语句,以检查程序的状态或条件是否满足预期。如果断言失败,会抛出一个AssertionError异常,提示开发人员该断言点存在问题。

例如org.springframework.util.Assert是Spring Framework中的一个工具类,用于进行参数校验和断言判断。它是一个包含静态方法的最终类。

org.springframework.util.Assert类中,提供了一系列静态方法用于进行断言操作,例如notNull()isTrue()hasText()等。这些方法主要用于验证方法参数或对象状态是否满足预期条件,如果不满足,则会抛出IllegalArgumentExceptionIllegalStateException等运行时异常。

常用的Assert方法源码如下:

//判断传入的表达式是否为true,如果为false,则抛出`IllegalArgumentException`异常,并使用指定的错误信息
public static void isTrue(boolean expression, String message) {if (!expression) {throw new IllegalArgumentException(message);}
}//判断传入的对象是否为null,如果为null,则抛出`IllegalArgumentException`异常,并使用指定的错误信息
public static void isNull(@Nullable Object object, String message) {if (object != null) {throw new IllegalArgumentException(message);}
}

org.springframework.util.Assert类中提供的方法可以帮助我们在编码过程中进行快速的参数校验,避免使用繁琐的if语句或手动抛出异常。同时,这些方法也提供了可自定义的错误信息,有助于更好地理解校验失败的原因。

什么是异常?

异常(Exception)是程序运行时出现的错误或异常情况,它会打断程序正常的执行流程,并且可能导致程序崩溃或产生不可预期的结果。在Java中,异常通常被表示为一个继承自Throwable类的对象,例如RuntimeException、IllegalArgumentException等。

而自定义异常是指开发人员基于Java中的Exception或其子类,定义自己的异常类。通常情况下,自定义异常类用于表示特定的异常情况,以便更好地对程序的异常情况进行分类处理和管理。自定义异常类可以包含自己的属性和方法,以提供更详细的异常信息和处理方式。

需要自定义异常的原因有以下几点:

  1. 更细粒度的异常控制:Java标准库中的异常类型比较全面,但是在实际应用中,我们可能需要更具体的异常类型来描述某种特定场景下的异常情况。例如,我们可以自定义一个PayErrorException来表示支付异常,这样可以更好地区分不同类型的异常情况,并进行不同的处理。

  2. 信息更丰富:Java标准库中的异常类型通常只包含错误信息,如果需要传递更多的相关信息,就需要自定义异常类。例如,我们可以在自定义异常类中添加一些额外的属性,如异常码、请求参数等,以便更好地记录和跟踪异常信息。

  3. 更友好的异常提示:Java标准库中的异常信息通常比较晦涩难懂,如果需要更加友好和易于理解的提示信息,就需要自定义异常类。通过自定义异常类,开发人员可以提供更加直观和易懂的异常提示信息,以便用户或其他开发人员更好地理解异常情况。

在实际业务中,我们往往需要设置一个全局的异常处理器对异常进行统一的处理和管理,并返回相应的错误信息,确保应用程序的稳定性和可靠性。

基于断言实现的异常处理机制

创建自定义异常类

首先,需要创建一个自定义的异常类,继承自RuntimeException或其子类:

/*** 自定义通用异常类*/
public class CommonException extends RuntimeException {/*** 无参构造方法*/public CommonException() {}/*** 构造方法,传入异常信息* @param message 异常信息*/public CommonException(String message) {super(message);}/*** 构造方法,传入异常信息和原始异常对象* @param message 异常信息* @param cause 原始异常对象*/public CommonException(String message, Throwable cause) {super(message, cause);}/*** 构造方法,传入原始异常对象* @param cause 原始异常对象*/public CommonException(Throwable cause) {super(cause);}
}

在自定义异常类CommonException中我们提供了几个不同的构造方法,方便在不同场景下创建异常对象。每个构造方法都调用了父类的构造方法super,以便初始化异常对象。

创建全局异常处理器

我们还需要创建一个全局异常处理器GlobalExceptionHandler,用于统一处理我们抛出的自定义异常类:

/*** 全局异常处理器*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 处理CommonException异常* @param e 异常对象* @return 异常信息*/@ExceptionHandler(CommonException.class)public String handleCommonException(CommonException e) {log.error("错误信息:{}", e.getMessage());return e.getMessage();}
}

在全局异常处理器GlobalExceptionHandler类上我们使用了@RestControllerAdvice注解标识该类为全局异常处理器。在该类中,定义了一个方法handleCommonException,用于处理异常捕获后的逻辑,在方法上添加了@ExceptionHandler()注解表示该方法处理指定自定义异常CommonException

创建自定义断言类

对于断言类,我们可以模仿org.springframework.util.Assert类,借鉴其中的方法,自定义一个抽象类MyAssert

/*** 断言类*/
public abstract class MyAssert {/*** 判断对象是否为空,如果不为空则抛出CommonException异常** @param object 要进行判断的对象*/public void assertIsNull(@Nullable Object object) {// 如果对象不为空,则抛出CommonException异常,并将当前对象序列化为JSON字符串作为异常信息if (object != null) {throw new CommonException(JSON.toJSONString(this));}}}

如上,我们创建了一个assertIsNull方法,参数object用于接收要进行判断的对象,如果object为空,则抛出CommonException异常,并将当前对象序列化为JSON字符串作为异常信息。

创建响应码类

创建自定义的响应码类,同时继承断言类MyAssert,这样我们可以通过响应码直接调用断言类中的方法进行判断:

/*** 响应码类,继承自断言类MyAssert*/
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ResCode extends MyAssert {/*** 响应码*/private int code;/*** 响应消息*/private String message;}

上述代码中,使用了Lombok库的注解来简化代码编写。具体注解的含义如下:

  • @Getter: 自动生成属性的getter方法。
  • @NoArgsConstructor: 自动生成无参构造方法。
  • @AllArgsConstructor: 自动生成包含所有参数的构造方法。

创建工具类

ResCodeUtils工具类用于调用响应码进行校验,抛出自定义异常并返回指定错误信息:

/*** 响应码工具类,继承自响应码类ResCode*/
public class ResCodeUtils extends ResCode {/*** 响应码naa,表示错误*/public static ResCode naa = new ResCode(300, "错误");/*** 响应码naa1,表示naa1错误*/public static ResCode naa1 = new ResCode(4044, "naa1错误");}

ResCodeUtils类中提供了两个静态属性naanaa1,分别表示响应码为300和4044的错误类型,方便通过类名.的方式直接调用。

测试效果

  1. 编写TestController类,添加@RestController注解表明该类是一个控制器类,用于处理HTTP请求并返回响应:

    @RestController
    public class TestController {@RequestMapping("/send1")public String send1() {ResCodeUtils.naa.assertIsNull(null);return "success";}@RequestMapping("/send2")public String send2() {ResCodeUtils.naa1.assertIsNull(new ResCode());return "success";}}
    

    TestController类中,定义了两个请求处理方法send1()send2()。这两个方法使用了@RequestMapping注解来指定它们对应的URL路径。

    • send1()方法中调用了ResCodeUtils.naa.assertIsNull(null),这表示对naa响应码进行断言,判断传入的参数是否为null。如果参数为null,断言通过,否则会抛出异常。

    • send2()方法中调用了ResCodeUtils.naa1.assertIsNull(new ResCode()),这表示对naa1响应码进行断言,判断传入的参数是否为null。由于参数new ResCode()不为null,所以这里会抛出异常。

    无论是send1()还是send2()方法,最终都会返回字符串"success"作为处理结果。

  2. 启动项目,使用 ApiFox 访问对应接口。

    • 访问send1(),由于参数为null,断言通过,返回字符串"success":

      image-20231101211357371

    • 访问send2(),由于参数为new ResCode(),不为null,断言未通过,抛出自定义异常之后被全局异常处理器GlobalExceptionHandler捕获,返回对应错误信息:

      image-20231101211431765

      同时,可以在控制台看到打印的日志信息

      image-20231101211511456


本文到此结束,感谢您的阅读,希望对您有所帮助!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/160552.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【QT】文件读写

新建项目 加入控件 整体做一个布局 功能&#xff1a;选择文件路径&#xff0c;打开文件&#xff08;两种文件格式&#xff1a;utf-8、GBK&#xff09; #include "widget.h" #include "ui_widget.h" #include <QPushButton> #include <QFileDial…

短视频账号矩阵系统saas源码搭建/技术

一、短视频矩阵系统建模----技术api接口--获取用户授权 技术文档分享&#xff1a; 本系统采用MySQL数据库进行存储&#xff0c;数据库设计如下&#xff1a; 1.用户表&#xff08;user&#xff09;&#xff1a; - 用户ID&#xff08;user_id&#xff09; - 用户名&#xff08…

shell综合项目

主菜单 http和Nginx分别的install的菜单&#xff0c;安装过程通过重定向到/dev/null达到看不见的效果 输入非整数或者大于4的数字都会提示错误 代码如下: [rootserver ~]# vim install_menu.sh #!/bin/bash function menu() { cat << EOF …

前端面试题之HTML篇

1、src 和 href 的区别 具有src的标签有&#xff1a;script、img、iframe 具有href的标签有&#xff1a;link、a 区别 src 是source的缩写。表示源的意思&#xff0c;指向资源的地址并下载应用到文档中。会阻塞文档的渲染&#xff0c;也就是为什么js脚本放在底部而不是头部的…

【实验记录】为了混毕业·读读论文叭

PR曲线 1. Robust_Place_Recognition_using_an_Imaging_Lidar 在第三节方法中&#xff0c;提到了一些列处理步骤&#xff0c;分析来与vins相似&#xff0c;在vins中是关键帧检索、特征提取、DBoW查询、描述子匹配、PnP RANSAC求解。 第四节的实验部分&#xff0c;没有绘制pr…

适用于 Linux 的 WPF:Avalonia

许多年前&#xff0c;在 WPF 成为“Windows Presentation Foundation”并将 XAML 作为 .NET、Windows 等的 UI 标记语言引入之前&#xff0c;有一个代号为“Avalon”的项目。Avalon 是 WPF 的代号。XAML 现在无处不在&#xff0c;XAML 标准是一个词汇规范。 Avalonia 是一个开…

curl(三)传递数据

一 基础铺垫 ① form表单回顾 关注&#xff1a; from 标签涉及 method、content-type等属性 enctype和Content-type有什么关系 ② Content-Type 思考&#xff1a;数据传输格式和解析类型不一致导致哪些特性? ③ application/x-www-form-urlencoded 1、GET方式 2、POST方…

前端使用firebase配置第三方登录介绍(谷歌登录,facebook登录等)

参考文档 点此处去 firebase 官网点此处去 web端的谷歌登录文档 实现 首先注册一个账号登录firebase&#xff08;可以使用谷歌账号登录&#xff09; 然后创建项目&#xff08;走默认配置就行了&#xff09; 添加应用&#xff08;走默认配置&#xff09;&#xff0c;如图所…

go语言 | grpc原理介绍(二)

gRPC gRPC 是一个高性能、通用的开源 RPC 框架&#xff0c;其由 Google 2015 年主要面向移动应用开发并基于 HTTP/2 协议标准而设计&#xff0c;基于 ProtoBuf 序列化协议开发&#xff0c;且支持众多开发语言。 由于是开源框架&#xff0c;通信的双方可以进行二次开发&#x…

【每日一题】数组中两个数的最大异或值

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;哈希集合 其他语言python3 写在最后 Tag 【哈希集合】【位运算-异或和】【数组】【2023-11-04】 题目来源 421. 数组中两个数的最大异或值 题目解读 找出数组中两个数的最大异或结果。 解题思路 一看数据量达到了 …

【Linux】 passwd命令使用

passwd命令用来更改使用者的密码。 语法 passwd [选项] [用户名] passwd命令 -Linux手册页 著者 克里斯蒂安加夫顿<gaftonredhat.com> 命令选项及作用 执行令 passwd --help 执行命令结果 参数 -k, --keep-tokens 保持身份验证令牌不过期-d, --delete …

接口测试之什么是接口文档?

一、为什么要有接口文档&#xff1f; 没有接口文档的接口测试都是在抓瞎~前面的接口测试重点讲了协议&#xff0c;也讲了fiddler模拟接口请求&#xff0c;估计大部分还是不太懂怎么下手测试。这里小编专门拿出接口文档来做接口测试参考&#xff08;估计很多测试小伙伴没见过接口…