异常吞没是错误发生却无日志、无告警、业务流程莫名跳过,需通过日志断层识别、全局异常钩子定位、清理高危catch模式及ci强制拦截来防控。

异常吞没不是代码报错,而是错误发生了却没人知道——日志里没痕迹、监控里没告警、业务流程莫名跳过。发现靠“断层”和“缺失”,避免靠规则和习惯。
看日志有没有“静默断层”
重点不是找 ERROR 日志,而是检查关键业务节点是否“该打的日志没打”。比如:
- 定时任务本该输出“开始处理订单”,但某次执行后整段日志消失
- 用户提交后既无“创建成功”,也无“校验失败”或“系统异常”日志
- 异步线程(如 pool-2-thread-1)的日志在某个操作后突然中断,后续步骤完全没记录
对比正常时段与异常时段的日志行数、关键标记(如“发送MQ前”“写库完成”),出现明显缺口,大概率有异常被 catch 块吃掉了。
用全局钩子确认异常去向
在应用启动时注册未捕获异常处理器,把所有逃逸的异常单独记入一个文件:
Thread.setDefaultUncaughtExceptionHandler((t, e) -> log.error("【Uncaught】线程 {} 异常", t.getName(), e));
如果问题发生期间这个日志是空的,说明异常没逃逸,而是被某处 catch 主动吞了;如果里面大量堆栈,则说明是异步路径(如 @Async、CompletableFuture、线程池 execute)中 try-catch 没罩住真正抛出点。
扫代码里的高危模式
以下 catch 写法基本等于埋雷,必须清理:
-
空块:
catch (Exception e) { }或catch (IOException e) { } - 仅 printStackTrace():输出到 System.err,在容器环境不可见
-
泛型捕获:
catch (Exception e)或catch (Throwable t),掩盖 NPE、OOM 等严重问题 - try-with-resources 中空 catch:资源打开失败或关闭失败都被静默忽略
- @Transactional 方法内 catch 后不抛出:事务不回滚,数据状态已错乱却无感知
IDE 通常会标红提示 “Swallowed exception”,别点 ignore;Code Review 时应把所有 catch 语句列为必查项。
进 CI 卡死源头
人工审查防不住漏网之鱼,必须让工具强制拦截:
- 在 SonarQube 或 Checkstyle 中启用 IllegalCatchCheck,禁止裸 catch 和空 catch
- 配置 SpotBugs 规则 RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT,识别被忽略的异常返回值
- CI 流水线中设置门禁:静态扫描不通过,不允许合入主干
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











