当前位置:网站首页>如何用断言思路优雅地处理代码异常
如何用断言思路优雅地处理代码异常
2022-07-16 07:28:00 【老王随聊】
目录
1、Assert(断言)
Assert大家都应该很熟悉了,比如在Spring项目中,单元测试经常会使用到 org.springframework.util.Assert包。
断言处理异常的作用:让编码异常处理更优雅。
以优雅的 Assert方式来校验业务异常情况,可以更多的让开发人员只关注业务逻辑,而不必花费大量精力写冗余的if else和 try catch 代码块。通过Assest的方式可以消灭 90% 以上的 try catch 代码块。
看看下面两段代码,你觉得哪个更丝滑?
public void testOrder2() {
// ... 省略
Order order = orderDao.selectById(orderId);
Assert.notNull(order, "订单不存在.");
}public void testOrder2() {
// ... 省略
Order order = orderDao.selectById(orderId);
if (order == null) {
throw new IllegalArgumentException("订单不存在.");
}
}第一种判定非空的写法相对比较优雅,而第二种写法则用 if {...} 代码块,显的冗余拖沓。那么 Assert.notNull() 底层的是怎么实现的呢?
public abstract class Assert {
public Assert() {
}
public static void notNull(@Nullable Object object, String message) {
if (object == null) {
throw new IllegalArgumentException(message);
}
}
}可以看到,Assert 其实就是帮我们把 if {...} 封装了一下。虽然简单,但不可否认的是,编码体验会上升很多。
基于这样的思路,我们不妨模仿org.springframework.util.Assert写一个断言类,不过断言失败后抛出的异常不是 IllegalArgumentException 这些内置异常,而是我们自己定义的异常。
2、如何自定义断言
2.1 自定义断言接口
自定义断言接口,封装异常类型。
package com.example.demo.exception;
/**
* 自定义断言
*/
public interface CustomAssert {
BaseException newException();
/**
* 创建异常
*
* @param args
* @return
*/
BaseException newException(Object... args);
/**
* 创建异常
*
* @param t
* @param args
* @return
*/
BaseException newException(Throwable t, Object... args);
/**
* 断言对象obj非空。如果对象obj为空,则抛出异常
*/
default void assertNotNull() {
throw newException();
}
/**
* 断言对象obj非空。如果对象obj为空,则抛出异常
*
* @param obj 待判断对象
*/
default void assertNotNull(Object obj) {
if (obj == null) {
throw newException(obj);
}
}
/**
* 断言对象obj非空。如果对象obj为空,则抛出异常
* 异常信息message支持传递参数方式,避免在判断之前进行字符串拼接操作
* @param obj 待判断对象
* @param args message占位符对应的参数列表
*/
default void assertNotNull(Object obj, Object... args) {
if (obj == null) {
throw newException(args);
}
}
}当断言失败后,抛出的异常不是具体的某个异常,而是交由 2 个 newException 接口方法提供。因为业务逻辑中出现的异常基本都是对应特定的场景,比如根据订单id 获取订单信息,查询结果为null,此时抛出的异常可能为 OrderNotFoundException,并且有特定的异常码(比如 100)和异常信息“订单信息不存在”。
所以具体抛出什么异常,由 CustomAssert 的实现类决定。
2.2 自定义响应枚举接口
定义统一的返回异常码和异常信息。将code和message定位为枚举类型,便于异常属性统一管理和参数传递。
package com.example.demo.exception;
/**
* 响应信息枚举值模板
**/
public interface IResponseEnum {
/**
* 错误编码
* @return 错误编码
*/
int getCode();
/**
* 错误信息
* @return 错误信息
*/
String getMessage();
}2.3 自定义响应枚举接口
后续业务基于这个枚举实现扩展所需异常类型即可。
package com.example.demo.exception;
/**
* 可扩展异常枚举
*/
public enum ResponseEnum implements BusinessExceptionAssert{
/** 系统异常 **/
SYSTEM_EXCEPTION(100, "系统异常"),
/** 对象不能为空 **/
OBJECT_IS_NULL(200, "{0}")
;
/**
* 返回码
*/
private int code;
/**
* 返回消息
*/
private String message;
ResponseEnum(int code, String message) {
this.code = code;
this.message = message;
}
@Override
public int getCode() {
return this.code;
}
@Override
public String getMessage() {
return this.message;
}
}2.4 基础异常信息封装
统一返回异常类。
package com.example.demo.exception;
/**
* 基础异常信息封装
*/
public class BaseException extends RuntimeException {
/**
* 错误码
*/
private int errorCode;
/**
* 错误信息
*/
private String errorMessage;
/**
* 传参
*/
private Object errorResult;
public BaseException(IResponseEnum iResponseEnum, String msg) {
super(msg);
this.errorCode = iResponseEnum.getCode();
this.errorMessage = iResponseEnum.getMessage();
this.errorResult = msg;
}
public BaseException(IResponseEnum iResponseEnum, Object[] args, String msg) {
super(msg);
this.errorCode = iResponseEnum.getCode();
this.errorMessage = iResponseEnum.getMessage();
this.errorResult = msg;
}
public BaseException(IResponseEnum iResponseEnum, Object[] args, String msg, Throwable t) {
super(msg);
this.errorCode = iResponseEnum.getCode();
this.errorMessage = iResponseEnum.getMessage();
this.errorResult = msg;
}
public BaseException(IResponseEnum iResponseEnum) {
super(iResponseEnum.getMessage());
this.errorCode = iResponseEnum.getCode();
this.errorMessage = iResponseEnum.getMessage();
}
public int getErrorCode() {
return errorCode;
}
public String getErrorMessage() {
return errorMessage;
}
public Object getErrorResult() {
return errorResult;
}
}2.5 业务异常信息封装
业务异常实现类。
package com.example.demo.exception;
/**
* 业务异常
**/
public class BusinessException extends BaseException {
private static final long serialVersionUID = 1L;
public BusinessException(IResponseEnum resp, Object[] args, String msg, Throwable t) {
super(resp, null);
}
public BusinessException(IResponseEnum resp, String os) {
super(resp, os);
}
public BusinessException(BusinessExceptionAssert businessExceptionAssert, Object[] args, String msg) {
super(businessExceptionAssert, args, msg);
}
public BusinessException(BusinessExceptionAssert businessExceptionAssert, Object[] args, String msg, Throwable t) {
super(businessExceptionAssert, args, msg, t);
}
}2.6 业务断言封装
package com.example.demo.exception;
import java.text.MessageFormat;
public interface BusinessExceptionAssert extends IResponseEnum, CustomAssert {
@Override
default BaseException newException() {
return new BusinessException(this, this.getMessage());
}
@Override
default BaseException newException(Object... args) {
String msg = MessageFormat.format(this.getMessage(), args);
return new BusinessException(this, args, msg);
}
@Override
default BaseException newException(Throwable t, Object... args) {
String msg = MessageFormat.format(this.getMessage(), args);
return new BusinessException(this, args, msg, t);
}
}2.7 测试类
package com.example.demo.exception;
/**
* 测试方法
*/
public class TestMain {
public static void main(String[] args) {
// ResponseEnum.SYSTEM_EXCEPTION.assertNotNull(); // 系统异常
ResponseEnum.OBJECT_IS_NULL.assertNotNull(null,"订单对象不能为空"); //对象不为空
}
}总结:我们可以通过上面的例子看到,实际业务代码基本不需要冗余太多的try catch块了。以上自定义断言主要参考了Spring中Assets的实现方式,对业务中经常使用的异常处理方式进行了很友好的封装。另外对于不同业务场景的异常来说,统一通过异常枚举类型来管理,也体现了很好的扩展性。
关注公众号,免费领取全部面试资料!
边栏推荐
- C language -- the implementation of common string functions
- Can SQL also do AI? you 're right! Mlops meetup V3 review openmlbd+sqlflow+byzer
- The most complete MySQL in history! Desperately tidy up
- Overcome the challenges of digital transformation by developing a vision
- Error establishing connection between MySQL and idea
- JS Object.keys()
- 物联网无线传输技术参数对比表
- OSS object storage process
- Realize chat room based on epoll (including timer to handle customer connection status)
- Talking about brain computer interface
猜你喜欢

Writing is more natural and comparable to the original factory experience. Nanka pencil capacitive pen is handy

Soft exam (intermediate software designer) exam information

软考(中级软件设计师)考试信息
![[server data recovery] a case of RAID5 data recovery of an IBM model storage](/img/7b/5c8b36ea91f0cef878a01b3c00f16f.jpg)
[server data recovery] a case of RAID5 data recovery of an IBM model storage

VS2019 16.8 “消失“的团队资源管理器

Small target detection 1_ Focal loss

Enable sandbox function and use in win10

MySQL field type selection

物联网无线传输技术参数对比表

Iowait understanding
随机推荐
Enable sandbox function and use in win10
Vulnhub-dc9 learning notes
[daily training] 558 Intersection of quadtree
【LeetCode】9. Flood fill · image rendering
全链路压测 :测试要做的准备工作
.net发布项目到服务器,文件形式
Splash integrates with Acronis to provide scalable remote support
The most complete MySQL in history! Desperately tidy up
Andersen global enters Rwanda
Kingbasees v8r6 cluster backup recovery case - the backup database performs physical backup as a repo host
gradle
OSS object storage process
[postponed] 2022 International Conference on network and information security (nisecurity 2022)
Codeforces Round #806 (Div. 4)
新功能上线需要发版本,回归测试中总是出现之前没有的问题
R语言---颜色选择和设置
澳大利亚规模领先的鞋业公司与Boomi合作以加快电子商务和转型步伐
Free SSL certificate application and deployment practice
ONNX模型tensor shapes inference和Flops统计工具
无线通信中LoRa技术特点