if (当前代码在抛出可预期异常) { (1)
处理异常()
} else if (根据我的分析, 这段代码会发生潜在异常) { (2)
if (需要关心这种异常) { (3)
处理异常()
}
} else {
// 再发生异常时就是我预测不到的, 我统称为 bug. (4)
}
17 一月 2020
对异常我们一般有这么几个处理方式:
我处理掉, 让上层无感知.
对异常进行封装, 封装成一个新的异常, 加入我的解释, 帮上层理解异常.
不做处理.
if (当前代码在抛出可预期异常) { (1)
处理异常()
} else if (根据我的分析, 这段代码会发生潜在异常) { (2)
if (需要关心这种异常) { (3)
处理异常()
}
} else {
// 再发生异常时就是我预测不到的, 我统称为 bug. (4)
}
1 | 众所周知, java 中异常分为可预期(excepted)异常和 runtime 异常. 为什么会有可预期异常这种东西? 帮助经验不足 java 程序员知道这段代码有发生哪些异常 |
2 | 比如有网络请求, 有参数校验等, 我知道这段代码可能会在某种可以想到的情况下发生异常 |
3 | 如何判断是否需要关心? 我当前的程序不需要较好的健壮性, 这个异常也不会影响到别人, 没有人因为这个异常没处理会感到疑惑或者背地里骂我, 那么我就可以不关心 |
4 | 我想象到不到会出现什么异常. 当然, 如果发生线上问题, 就要背锅交学费了 |
判断完是否要处理异常, 如果需要处理, 就要看看如何处理异常:
function 处理异常(ex) {
if (我在非业务逻辑中) { (1)
pass:q[**处理非业务异常(ex)**]
} else if (我在业务逻辑中) {
处理业务异常(ex)
}
}
1 | 什么叫非业务异常? 跟业务逻辑无关的中立代码. 比如 发送 HTTP 请求的工具类 , 初始化项目基础设施的代码 |
非业务代码中的异常, 一般是无法原地处理的, 都是要抛给上层, 让真正知道业务的地方去判断出了这种问题该如何处理.
function 处理非业务异常(ex) {
if (我很确定重试后成功的概率很高) { (1)
do: 考虑尝试 1-2 次
如果成功就 ok, return
}
do: 抛出特定异常, 说明错误原因, 带上原始异常. 最好带上特定 异常 code, 带有结构化的数据能够对异常做详细说明 (2)
}
1 | 一般都是不能抢救的. 例外的, 比如创建链接超时这种不确定异常, 可以重试下, 很多 HTTP 请求框架也是有这么做的. |
2 | 一个包含了足够信息的异常. 一个更有表现里的异常 |
业务逻辑中处理异常会稍微复杂一些, 到这里已经不是一个技术问题, 而是个业务思维问题了.
先看流程吧:
function 处理异常(ex) {
if (业务逻辑不需要回滚) {
if (这种异常不需要处理, 或者可以被自动处理) {
do: warn 日志|错误计数
return
} else {
do: error 日志
return
}
}
if (不符合业务逻辑规则, 我可以抛给用户, 可以让用户知道发生了什么, 并且能够理解的) { // 非 bug
do: 抛出 ServiceException, 带上错误 tip. 在用户接口层对这个错误进行处理, 返回提示, 打印 warn 日志, 或进行审计计数.
return
} else if (不符合业务逻辑规则, 但是也没有办法通知用户到用户的) {
return
} else if (系统内部运行不符合预期的) { // bug 或 问题
do: 抛出 ServiceErrorException, tip: 系统错误. 统一 catch 输出异常提示, 打 error 日志
return
}
}
<1> <2> 通常是我不能处理的, 因为我不知道这个异常对于整个业务逻辑有着什么影响, 所以一般都是不能抢救的. 例外的, 对于创建链接超时这种不确定异常, 可以重试下, 很多 HTTP 请求框架也是有这么做的.
warn 日志 - 不太需要关注, 通常可以自动恢复
error 日志 - 错误, 需要报警关注
异常收集计数 report
通常不太需要关注, 但是达到某种阈值会变成问题.
需要定期例行关注下.