1、为什么要这样做

在上一篇最终提到便是面对事务代码中出现反常的状况,假如不处理,则展现给用户的信息是十分不友好的。比方以下代码出现空指针时

代码优雅之道——断言 + 统一异常处理

那么前端得到的响应是啥样?

代码优雅之道——断言 + 统一异常处理

此外在事务代码中可能会用许多的校验,有的校验回来一些提示信息,有的校验可能需要抛出指定的反常。

通常咱们运用try {…} catch {…} finally {…} 代码块来处理反常,而这些反常咱们是不能直接展现给用户。所以对反常进行分类一致处理,削减冗余代码,使代码风格一致更高雅。

2、断语处理

像上图中一个代码块中会有许多的校验,而实践项目中非空或许一些事务判断都是很频繁的。咱们来改造一下上图中的代码,运用断语后两行代码就处理了

代码优雅之道——断言 + 统一异常处理

到这儿不必看源码大家必定也现已猜到了,它必定用的if(){}

代码优雅之道——断言 + 统一异常处理

是null就抛出反常,而state()却不相同,为false时抛出反常,所以这儿的表达式填咱们想要的成果。

代码优雅之道——断言 + 统一异常处理

用之前去Assert类中看一看,多用几次天然就熟练了,开发起来也会愈加的快速。

实践项目中咱们可能还需要调用其他服务暴露出来的接口,调用失利后抛出自定义的反常

代码优雅之道——断言 + 统一异常处理

此刻咱们也能够写个断语工具类

public class AssertUtil {
    /**
     * 服务调用反常
     * @param expression
     * @param message
     */
    public static void isTrueServiceInvoke(boolean expression, String message) {
        if (!expression) {
            throw new ServiceInvokeException(message);
        }
    }
}

那么这一类问题,都能够运用,处理了代码冗余问题

代码优雅之道——断言 + 统一异常处理

3、一致反常处理

通过以上描绘咱们也能够看出,项目中除了空指针这种反常,还有断语抛出的反常,还有自定义反常,对各种各样的反常一致处理,使得回来愈加友好的信息。

主要通过 @RestControllerAdive 提高作用域,通过 @ExceptionHandler 注解来处理不同的反常。

import com.example.assertdemo.common.exception.ServiceInvokeException;
import com.example.assertdemo.constant.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    @ResponseBody
    @ExceptionHandler(NullPointerException.class)
    public ApiResult nullPointerExceptionHandler(NullPointerException exception) {
        log.error(exception.getMessage());
        return ApiResult.fail(ResultCodeEnum.SERVE_EXCEPTION);
    }
    @ResponseBody
    @ExceptionHandler(ServiceInvokeException.class)
    public ApiResult serviceInvokeExceptionHandler(ServiceInvokeException exception){
        log.error(exception.getMessage());
        return ApiResult.fail(ResultCodeEnum.SERVE_EXCEPTION);
    }
}

回来的状况码和提示信息搞个枚举类

@Getter
public enum ResultCodeEnum{
    /**
     * success
     */
    SUCCESS(0,"操作成功"),
    /**
     * fail
     */
    FAIL(-1,"操作失利"),
    /**
     * 参数过错:1001-1999
     */
    PARAM_IS_INVALID(1001,"参数无效"),
    PARAM_TYPE_ERROR(1002,"参数类型过错"),
    /**
     * 事务过错:2001-2999
     */
    TERMINATE_CONTRACT_FAIL(2001,"停止合同失利,请联络管理员"),
    SERVE_EXCEPTION(3001,"当时服务出小差了,请联络管理员"),
    ;
    /**
     * 状况码
     */
    private final int code;
    /**
     * 提示信息
     */
    private final String message;
    ResultCodeEnum(Integer code, String message){
        this.code = code;
        this.message = message;
    }
}

此刻咱们再去恳求2、断语处理中的接口,这种提示就十分友好,不会给用户展现看不懂的一连串反常信息,还能让开发者及时定位到问题去处理。

代码优雅之道——断言 + 统一异常处理

代码优雅之道——断言 + 统一异常处理

4、断语类中的办法

说白了许多办法便是填入你期望的成果,比方isTrue(a==1,””),也便是我期望a等于1,假如不等于就抛出反常。

目标和类型断语

办法

阐明

notNull()

目标是null抛出反常

isNull()

目标不是null抛出反常

isInstanceOf()

查看目标必须为另一个特定类型的实例

isAssignable()

查看类型

文本断语

办法

阐明

hasLength()

只需不是null和空字符串就不会报反常

hasText()

增强查看条件,字符串至少包括一个非空白字符,能够运用hasText()办法

doesNotContain()

查看参数不包括特定子串

逻辑断语

办法

阐明

isTrue()

条件为假抛出IllegalArgumentException 反常

state()

该办法与isTrue相同,但抛出IllegalStateException反常

Collection和map断语

办法

阐明

Collection使用notEmpty()

Collection不是null并包括至少一个元素

map使用notEmpty()

查看map不null,并至少包括一个entry(key,value键值对)

数组断语

办法

阐明

notEmpty()

能够查看数组不null,且至少包括一个元素

noNullElements()

确保数组不包括null元素