应杜绝捕获Throwable或泛型Exception,只捕获具体异常类型;受检异常须显式处理而非静默吞掉;finally中勿覆盖原始异常;自定义异常需依场景选择继承RuntimeException或Exception。

杜绝捕获 Throwable 或泛型 Exception 的习惯,关键不在“加限制”,而在建立清晰的异常分层意识和落地的工程约束。这不是靠意志力记住“不能写”,而是让错误写法在编码、编译、测试阶段就暴露出来,并提供更自然的替代路径。
用静态检查工具主动拦截
这类宽泛捕获属于可检测的代码异味,IDE 和构建工具能第一时间亮红灯:
- 启用 IDE(如 IntelliJ)的 inspections:勾选 “Catch Exception”、“Catch Throwable” 警告,设为 error 级别;
- 在 Maven/Gradle 中集成 SpotBugs 或 ErrorProne,配置规则
REC_CATCH_EXCEPTION和THROWABLE_INSTANCEOF,CI 流水线失败即阻断; - 阿里巴巴 Java 开发手册插件(Alibaba Java Coding Guidelines)会直接标出所有
catch (Exception e)并提示“应捕获具体异常类型”。
把“兜底逻辑”上移到统一入口
业务方法里不需要、也不该承担兜底责任。真正需要“吃掉异常并转成友好响应”的地方非常有限:
- Web 层:用
@ControllerAdvice+@ExceptionHandler统一处理IOException、SQLException等已知异常,对RuntimeException记录后返回 500; - RPC/SDK 调用层:仅在网关、客户端代理等少数边界处用
catch (Throwable t),且必须记录完整堆栈并快速失败(如返回降级结果),不继续执行后续业务; - 绝不允许在 service、util、dao 等中间层出现
catch (Exception e)—— 它们只负责抛出或转换异常。
用 try-with-resources 和防御式编程减少捕获需求
很多看似“必须 catch”的场景,其实源于资源管理和输入校验不到位:
立即学习“Java免费学习笔记(深入)”;
- 文件流、数据库连接、HTTP 客户端等实现
AutoCloseable的资源,一律用try-with-resources,省去finally和可能误写的catch; - 对空值、非法参数、格式错误等,优先做前置校验:
Objects.requireNonNull()、StringUtils.isBlank()、正则预匹配,而不是等NullPointerException或NumberFormatException抛出来再 catch; - 例如解析 JSON 字符串,先用
JsonParser非严格模式试探,或封装成safeParseJson()方法内部处理JsonProcessingException,对外只暴露明确语义的业务异常。
建立团队级异常分类规范
统一什么是“可恢复异常”、什么是“该修复的 bug”,比单靠语法约束更治本:
- 定义三类异常使用边界:
• Checked 异常(如IOException):调用方必须显式处理,代表外部依赖的不确定性;
• 业务异常(继承RuntimeException):如InsufficientBalanceException,用于流程控制,不打 ERROR 日志;
• 系统异常(未检查的运行时异常):如NullPointerException,属于缺陷,不捕获,靠单元测试和 Code Review 暴露; - 在接口文档和 Swagger 注释中明确标注每个方法可能抛出的异常类型,倒逼开发者思考“这个异常我真要在这里处理吗?”


















