
在上一篇最后提到就是面对业务代码中出现异常的情况,如果不处理,则展示给用户的信息是非常不友好的。比如以下代码出现空指针时

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

此外在业务代码中可能会用很多的校验,有的校验返回一些提示信息,有的校验可能需要抛出指定的异常。
通常我们使用try {...} catch {...} finally {...} 代码块来处理异常,而这些异常我们是不能直接展现给用户。所以对异常进行分类统一处理,减少冗余代码,使代码风格统一更优雅。
像上图中一个代码块中会有很多的校验,而实际项目中非空或者一些业务判断都是很频繁的。我们来改造一下上图中的代码,使用断言后两行代码就解决了

到这里不用看源码大家肯定也已经猜到了,它肯定用的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);
- }
- }
- }
那么这一类问题,都可以使用,解决了代码冗余问题

通过以上描述我们也可以看出,项目中除了空指针这种异常,还有断言抛出的异常,还有自定义异常,对各种各样的异常统一处理,使得返回更加友好的信息。
主要通过 @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、断言处理中的接口,这种提示就非常友好,不会给用户展示看不懂的一连串异常信息,还能让开发者及时定位到问题去处理。


说白了很多方法就是填入你希望的结果,比如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元素 |