应只捕获明确知道如何处理的具体异常类型,避免catch(Exception)或catch(Throwable),否则会掩盖问题、丢失栈信息、破坏异常传播;RuntimeException子类须修复逻辑而非捕获;优先用多catch、try-with-resources和@ControllerAdvice统一处理。

捕获 Exception 会掩盖真正的问题类型
Java 的异常体系里,Exception 是所有检查型异常(checked)和非检查型异常(unchecked)的父类。一旦你写 catch (Exception e),连 NullPointerException、IllegalArgumentException 这种明显是编程错误的异常也会被吞掉——它们本该在开发阶段暴露,而不是被统一兜底。
常见错误现象:本地测试一切正常,上线后某个空指针被静默吃掉,业务逻辑跳过关键步骤,数据不一致却无日志可查。
- 只捕获你明确知道如何处理的异常类型,比如调用 HTTP 接口时捕获
IOException或TimeoutException - 对
RuntimeException子类(如NullPointerException、ArrayIndexOutOfBoundsException)不要 catch,应修复代码逻辑 - 如果真需要“兜底”,也应在最外层(如 Spring 的
@ControllerAdvice)做统一处理,而非在业务方法里盲目 catch
Throwable 比 Exception 更危险:它包含 Error
Throwable 是 Java 异常体系的顶层,它下面分两支:Exception 和 Error。Error 表示 JVM 级别的严重问题,比如 OutOfMemoryError、StackOverflowError、NoClassDefFoundError。这些不是程序能“恢复”的,强行 catch 只会让状态更不可控。
使用场景:几乎不存在合理场景需要捕获 Throwable。有人为“防崩”加这一句,结果 OOM 发生后线程卡死,JVM 已无法保证后续行为。
- 绝对不要写
catch (Throwable t),IDE 通常会标红警告,别忽略 -
Error不该被应用代码处理,而是靠监控、重启、堆内存调优等运维手段应对 - 如果框架强制你声明抛出
Throwable(极少见),优先看文档是否支持更具体的异常类型替代
宽泛捕获破坏异常传播语义和日志可追溯性
异常本质是一种控制流信号。当你用 catch (Exception e) 捕获后又简单 e.printStackTrace() 或只打一条“发生异常”日志,就等于把原始栈信息、异常类型、触发上下文全丢掉了。下游排查时看到的是一条模糊日志,而不是 SQLSyntaxErrorException: Unknown column 'user_nam' in 'field list' 这样带字段名的精准提示。
性能影响不大,但可维护性断崖式下降——尤其是多层嵌套调用中,宽泛 catch + 无差别 rethrow(或不 rethrow)会让问题定位时间翻倍。
- 每个
catch块必须有明确目的:重试?降级?转译为业务异常?否则不如不写 - 记录日志时,用
log.error("query user failed", e)而不是log.error("query user failed: " + e.getMessage()),否则丢失栈轨迹 - 避免在 finally 里吞异常;更别在 catch 里又 throw new RuntimeException(e),除非你清楚封装意图且上层能识别
替代方案:用具体异常 + 多 catch 或 try-with-resources 更安全
Java 7+ 支持多异常捕获语法,配合明确的资源管理,既能覆盖必要分支,又不扩大范围。比如文件读取操作,与其 catch Exception,不如分别处理 FileNotFoundException(路径错)、SecurityException(权限不足)、IOException(磁盘满),每种对应不同响应策略。
示例:
try (FileInputStream fis = new FileInputStream(path)) {
// ...
} catch (FileNotFoundException e) {
log.warn("config file missing, use defaults", e);
return defaultConfig();
} catch (IOException e) {
throw new AppConfigLoadException("failed to read config", e);
}
- 优先用 try-with-resources 管理资源,避免因异常导致资源泄漏,比手动 try-catch-finally 更可靠
- Spring 等框架提供
@ExceptionHandler,适合把同类异常集中处理,避免重复代码 - 自定义异常时,继承
RuntimeException还是Exception要想清楚:是否强制调用方处理?多数业务异常建议用 unchecked
真正难的不是写对 catch,而是判断“这里到底该不该 catch”。很多异常本就不该被捕获,而应该让调用链自然向上抛,直到有语义明确的处理点。越早放弃“全兜住”的想法,代码越不容易在深夜报警时让你摸不着头脑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











