AI 辅助 Java 异常处理:让报错信息真正帮你定位问题
生产环境最常见的求助场景不是代码写不出来,而是报错看不懂:一段堆栈贴到群里,十分钟没人回;自己顺着堆栈往上翻,翻到第三层就断了。AI 在这个环节最有用的地方,不是替你改代码,而是帮你把“报错信息”翻译成“问题定位”。
一、先让 AI 读堆栈,而不是直接让它改代码
很多人一看到异常就把整段堆栈加一句“帮我修”丢给 AI,得到的多半是一段看起来合理、实际跑不通的补丁。更有效的做法是分两步:先问“这段堆栈说明什么”,再问“怎么修”。
一个好用的提问模板是:异常类型 + 触发入口 + 关键帧 + 已确认的事实。比如:
NullPointerException,入口是订单查询接口,堆栈顶层在OrderService.getDetail第 42 行,已确认入参 orderId 非空、数据库里有这条订单。
带着事实提问,AI 才能把注意力放在真正的可疑点上——比如第 42 行调用的对象是不是某个未初始化的依赖,而不是泛泛地讲一遍空指针的成因。
二、异常要分层,不要全抛 RuntimeException
AI 生成代码时最容易偷懒的一点,就是把所有异常都包成 RuntimeException 往外抛。短期省事,长期代价很大:调用方分不清哪些是能重试的、哪些是参数错了、哪些是下游挂了。
一个够用的分层是三类:
- 参数类异常:入参非法,调用方改参数就能解决,不应重试。
- 业务类异常:规则不满足,比如库存不足,返回明确的业务提示。
- 系统类异常:数据库、下游服务、网络问题,可以重试或降级。
让 AI 帮你审代码时,可以直接问:“这段代码里哪些异常被吞掉了?哪些该分层、哪些该重试?”它对“吞异常”这类模式问题很敏感,常能一眼指出 catch (Exception e) { log.info("error"); } 这种把错误静默吃掉的写法。
三、日志要让 AI 能接着查,而不是只能给人看
定位问题靠的不是某一条日志,而是日志之间的关联。三个习惯值得坚持:
- 一次请求一个 traceId,从入口一路透传到下游调用,查问题先按 traceId 聚合。
- 异常日志记全三要素:发生了什么、关键上下文(订单号、用户 ID)、完整的堆栈。只记一句
error occurred的日志,AI 也帮不上忙。 - 错误日志与业务日志分级:
WARN给可恢复的业务异常,ERROR只给需要人介入的系统异常。满屏 ERROR 等于没有 ERROR。
// 全局异常处理:业务异常返回明确提示,系统异常记全上下文
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusiness(BusinessException e) {
// 业务异常:不记堆栈,返回业务码即可
log.warn("业务异常 code={} msg={}", e.getCode(), e.getMessage());
return Result.fail(e.getCode(), e.getMessage());
}
@ExceptionHandler(Exception.class)
public Result<Void> handleSystem(Exception e, HttpServletRequest request) {
// 系统异常:记 traceId + 请求路径 + 完整堆栈,供后续定位
log.error("系统异常 path={} traceId={}",
request.getRequestURI(), MDC.get("traceId"), e);
return Result.fail("SYSTEM_ERROR", "系统繁忙,请稍后重试");
}
}
四、AI 给出的根因,一定要用一次复现验证
AI 分析堆栈时偶尔会“自信地猜错”:把并发问题说成配置问题,把时序问题说成空指针。判断标准很简单:按它说的根因,能不能在本地或测试环境稳定复现一次?能复现,再修;复现不了,先补日志、缩小范围,不要直接按它的结论改生产代码。
一个实用的收尾流程是:AI 定位 → 本地复现 → 最小修复 → 补一条回归测试覆盖这个异常分支。下次同样报错再出现,测试先报警,定位就不用从零开始。
小结
AI 改变的不是异常本身,而是处理异常的顺序:先读懂报错、再分层处理、靠结构化日志定位、最后用复现验证结论。报错信息不再是让人头疼的乱码,而是定位问题的起点——前提是,代码先把该记的信息记全。
- 点赞
- 收藏
- 关注作者
评论(0)