异常处理-断言和枚举封装异常

文章目录

  • 简介
  • 参考
  • 实践
    • 基础断言
      • 定义一个基础的异常
      • 定义一个基础的断言
    • 业务
      • 定义业务异常
      • 业务的断言
    • 枚举
    • 测试
  • 优化
  • 思考
    • 为什么使用接口
    • 业务的异常和业务断言是否可以添加

简介

下面代码分别采用普通模式和断言的模式书写,断言其实是内部封装了判断,然后抛出异常,所以看起来就非常简洁。

   @Test
    public void test1() {
        Order order = orderDao.selectById(orderId);
        Assert.notNull(order, "订单不存在。");
    }

    @Test
    public void test2() {
        // 另一种写法
        Order order = orderDao.selectById(orderId);
        if (order == null) {
            throw new IllegalArgumentException("订单不存在。");
        }
    }

参考

用Assert(断言)封装异常,让代码更优雅(附项目源码):点击跳转

实践

基础断言

定义一个基础的异常

@NoArgsConstructor
@AllArgsConstructor
@Data
public class BaseException extends RuntimeException {
    /**
     * 异常信息
     */
    private String message;
}

定义一个基础的断言

/**
 * 这里模仿Assert的isNull的写法,
 * Assert是抽象类,这里采用接口,所以需要default定义
 * 唯一不同的地方是这里不定义具体的异常,该异常由各自的处理器自定义
 *
 * @author zhangfanjun
 * @date 2022/5/17
 * @see Assert#isNull(Object, String) 断言判断null
 */
public interface AssertHandler {


    /**
     * 没有入参的异常,这个处理主要是返回枚举的参数进行创建异常
     *
     * @return 异常
     * @author zfj
     * @date 2022/5/17
     */
    BaseException newException();

    /**
     * 提供默认的异常返回,如果需要返回项目的自定义异常,就需要重写该方法
     *
     * @param message 异常的信息
     * @return 自定义的基础异常
     * @author zfj
     */
    default BaseException newException(String message) {
        return new BaseException(message);
    }

    /**
     * 基础方法
     * Supplier提供get方法
     *
     * @param messageSupplier Supplier表达式
     * @return 字符串
     * @author zfj
     */
    default String nullSafeGet(Supplier messageSupplier) {
        return messageSupplier != null ? messageSupplier.get() : null;
    }

    /**
     * 判断null,这个时候采用自定义的异常来进行处理
     *
     * @param object 入参
     * @author zfj
     */
    default void isNull(Object object) {
        if (object != null) {
            throw newException();
        }
    }

    /**
     * 判断null
     *
     * @param object  入参
     * @param message 异常信息
     * @author zfj
     */
    default void isNull(Object object, String message) {
        if (object != null) {
            throw newException(message);
        }
    }

    /**
     * 判断null
     *
     * @param object          入参
     * @param messageSupplier 异常信息表达式
     * @author zfj
     */
    default void isNull(Object object, Supplier messageSupplier) {
        if (object != null) {
            throw newException(nullSafeGet(messageSupplier));
        }
    }
}

业务

定义业务异常

@Data
public class BusinessException extends BaseException {
    /**
     * 异常的
     */
    private int code = 500;
    /**
     * 异常信息
     */
    private String message;

    public BusinessException() {
    }

    public BusinessException(String message) {
        this.message = message;
    }

    public BusinessException(int code) {
        this.code = code;
    }

    public BusinessException(int code, String message) {
        this.code = code;
        this.message = message;
    }
}

业务的断言

public interface BusinessExceptionAssert extends AssertHandler {

    /**
     * 重写方法返回自定义的异常,用于项目自定义的异常捕捉
     * BaseException也有默认的属性保存message,所以不重写就返回默认的异常
     * @param message 异常信息
     * @return 返回自定义的异常
     * @author zfj
     */
    @Override
    default BaseException newException(String message) {
        return new BusinessException(message);
    }
}

枚举

@Getter
@AllArgsConstructor
public enum BusinessExceptionEnum implements BusinessExceptionAssert {
    NOT_FOUND(500, "没有找到"),
    NOT_EXIST(500,"不存在"),;

    private int code;
    private String message;

    @Override
    public BaseException newException() {
        return new BusinessException(code,message);
    }
}

测试

想想这个无法满足需求,判断null,判断等于某个值,确实可以,但是业务处理中经常面临复杂的判断逻辑,这个场景下就不能满足了

    @Test
    void test1(){
        String s = new String();
        BusinessExceptionEnum.NOT_EXIST.isNull(s);
        BusinessExceptionEnum.NOT_EXIST.isNull(s,()->{
            return "222";
        });
    }

优化

@FunctionalInterface
public interface AssertFunction {

    /**
     * 断言
     *
     * @return 断言结果
     * @author zfj
     * @date 2022/5/18
     */
    boolean check();
}

自定义的断言接口中增加一个默认方法

    /**
     * 断言
     *
     * @param f 断言函数
     * @author zfj
     * @date 2022/5/18
     */
    default void check(AssertFunction f) {
        boolean check = f.check();
        if (check){
            throw newException();
        }
    }

测试

        System.out.println("测试断言");
        BusinessExceptionEnum.NOT_EXIST.check(()->{
            return true;
        });

思考

为什么使用接口

不管是使用抽象方法或者抽象类,主要的目的是添加抽象方法,抽象方法必须被实现,所以就有了枚举类自定义了返回的异常。

业务的异常和业务断言是否可以添加

可以,原本的断言的BaseException就能使用的,只是只有一个字段message,也可以将BaseException定义成项目业务的异常。

你可能感兴趣的:(java)