异常处理规范

try-catch代码块竟可能小范围

保证try-catch的代码块尽可能小,以保证catch不会捕获你为意识到的异常,特别是可能抛出的空指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// badcase
private void doSomething() {
try {
URL url = new URL("");
String path = url.getPatch();
......
// 省略10086行
......
} catch (Exception e) {
dealException();
return;
}
}

// better case
private void doSomething() {
URL url = null;
try {
URL url = new URL("");
} catch (MalformedURLException e) {
dealException();
return;
}
String path = url.getPatch();
......
// 省略10086行
......
}

尽可能捕获明确的异常

配合第1点,代码块尽量小时,可以捕获更加明确的异常。

时刻提醒自己可能出现其他异常。

使用断言

此断言非java的 assert 关键字, 可以使用Spring 的Assert类

所有public的接口调用, RPC远程调用。都是不可靠的。

为了减少空指针异常带来的不确定性(NPE),请善用断言(Assert),fail-fast 逻辑。

仅在按照约定,某个事件必不可能发送,一旦发生,你的业务逻辑也并无其他处理方案时(没有fallback)使用断言。

使用断言配合message,可以快速的在日志,报警或者其他可视化系统中,发现并定位问题,也能给前端正确的异常提示,减少用户焦虑,加快排查问题的速度。

1
2
3
4
5
6
7
8
9
10
11
12
13
// better case
private void doSomething(Doc doc) {
Assert.notNull(doc, "doSomething时,文档不应该为空");
Long id = doc.getId();
......
}

private void doSomething2(Long id) {
Doc doc = docService.getDocById(id);
Assert.notNull(doc, "doSomething2时,根据id查询doc,文档不应该为空, id:" + id);
String name = doc.getName();
......
}

不厌其烦的判空

  1. 会触发自动拆箱时。 如:

    1
    2
    3
    4
    5
    int a = someInteger 

    if (some int == some Integer)

    if (some Boolean)
  2. 嵌套对象取值时:

    1
    Long id = userInfoDTO.getUserInfo().getUserId();
  3. 从redis,数据库或其他DB获取值时。

  4. 调用其他人书写的方法时。

  5. ⚠️调用自己,或第三方jar包提供的工具类时, 特别是:

   parse

   get

   transform

  1. 参数校验写明message
1
2
3
4
5
6
7
8
9
10
// badcase
@NotNull
private Long userId;

@NotBlank
private String name;

// better case
@NotNull("userId不能为空")
private Long userId;
  1. 使用工具类判空

优先使用

  • Objects.equals(a, b)
  • StringUtils.isBlank(a);
  • StringUtils.isNotBlank(a);
  • CollectionUtils.isEmpty(a);

等工具类判断对象或者数据结构。

  1. GlobalException的使用

⚠️使用更精准的异常信息。

不要单纯的使用 ResponseCodeEnum.FAIL,(即9999报错)

对于特定的报错,请使用定义好的ResponseCode, 且他的message必须清晰。

如果觉得务必要新建ResponseCode, 也应该使用 GlobalException(ResponseCodeEnum code, String message); 构造方法, 把详细的报错信息放入Exception中。

不要单纯的使用 ResponseCodeEnum.FAIL,(即9999报错)

对于特定的报错,请使用定义好的ResponseCode, 且他的message必须清晰。

如果觉得务必要新建ResponseCode, 也应该使用 GlobalException(ResponseCodeEnum code, String message); 构造方法, 把详细的报错信息放入Exception中。