应避免捕获 Throwable,因其混同 Error 与 Exception,掩盖严重问题并破坏异常语义边界;仅捕获具体 Exception 子类型,按层级精准处理,工具链(IntelliJ、SpotBugs、阿里规范插件)强制约束,结合 try-with-resources 和前置校验减少异常发生。

避免捕获 Throwable,核心是切断它对异常分类体系的“越界覆盖”——Throwable 同时包含 Error(如 OutOfMemoryError)和 Exception(含受检与非受检),一并捕获就等于把系统崩溃、JVM错误和业务异常混为一谈,既掩盖严重问题,又破坏异常语义边界。
只捕获明确的 Exception 子类型
受检异常(如 IOException、SQLException)和非受检异常(如 IllegalArgumentException、NullPointerException)本就该由不同层级、不同策略处理。捕获 Exception 已属宽泛,捕获 Throwable 更是越界。
- 业务逻辑中,应按实际可能抛出的异常类型逐层 catch:比如文件操作优先捕获
FileNotFoundException和SecurityException,而不是笼统写catch (Exception e) - 绝对禁止
catch (Throwable t)出现在 service、dao、util 等中间层;它只允许出现在极少数边界入口(如 RPC 网关、Servlet 容器顶层),且必须附带完整堆栈日志 + 快速失败(如返回降级响应) - 若真需兜底(例如监控 agent 或框架启动器),也应先过滤
Error:if (t instanceof Error) { throw t; },再处理真正可干预的Exception
用编译器和工具守住底线
靠人工记忆容易疏漏,要把约束嵌入开发流程。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 在 IntelliJ 中启用 inspection:搜索 “Catch Throwable”,设为 error 级别,保存即报红
- Maven/Gradle 集成 SpotBugs,启用规则
REC_CATCH_EXCEPTION和THROWABLE_INSTANCEOF,CI 构建失败即阻断 - 安装阿里巴巴 Java 开发规范插件,它会直接标出所有
catch (Throwable t)并提示“禁止捕获 Throwable,应使用具体异常类型”
分清受检异常的处理责任归属
受检异常不是“必须被 catch”的负担,而是设计上要求“必须被显式决策”的契约。混淆常源于把它塞进不该负责的地方。
立即学习“Java免费学习笔记(深入)”;
- DAO 层抛出
SQLException,Service 层不捕获,而是声明throws SQLException或转为更语义化的业务异常(如AccountLockedException) - Controller 层才集中处理:用
@ExceptionHandler拦截已知受检异常(如IOException),统一转为 HTTP 400/500 响应;非受检异常则记录后返回 500,并避免吞掉堆栈 - 绝不允许在工具类或通用方法里用
try-catch静默吞掉受检异常(如catch (IOException e) { return null; }),这等于主动放弃契约,制造隐蔽缺陷
用 try-with-resources 和校验替代“防御式 catch”
很多看似需要捕获 Throwable 的场景,其实源于资源管理粗放或输入校验缺失。
- 所有实现
AutoCloseable的资源(FileInputStream、Connection、HttpClient)一律用try-with-resources,自动释放,无需finally,也大幅减少因资源未关闭引发的连锁异常 - 对参数做前置校验:用
Objects.requireNonNull()、StringUtils.isNotBlank()、正则预匹配等,把NullPointerException、IllegalArgumentException拦在执行前,而非等运行时抛出再 catch - 封装高危操作为安全方法:例如
safeParseJson(String)内部处理JsonProcessingException,对外只抛出明确业务异常或返回Optional,调用方无需面对底层异常细节

















