java多catch关键在于兼顾整洁与精细:子类异常前置、同类异常用|合并、无关逻辑外提、资源清理交由try-with-resources;jvm按顺序匹配,命中即止;兜底catch需记录完整堆栈;multi-catch要求异常无继承关系,e为公共父类类型。

Java里多catch编写时,关键不是在“整洁”和“精细”之间做取舍,而是用对方式让两者同时成立:子类异常分写、同类异常合并、无关逻辑外提、资源清理自动完成。
按继承关系从具体到宽泛排列
这是避免逻辑失效的底线。JVM按catch出现顺序匹配,一旦命中就停止后续检查。
- 把 ArithmeticException、NullPointerException、ArrayIndexOutOfBoundsException 这类明确可定位的异常写在最前面
- 中间放业务自定义异常,如 InsufficientBalanceException、InvalidOrderStatusException
- 最后才用 Exception 或 RuntimeException 做兜底,且必须记录完整堆栈(不能只打
e.getMessage())
相同处理逻辑用 multi-catch 合并
Java 7+ 的竖线语法不是炫技,是为消除重复代码而生。
- 写法:
catch (IOException | SQLException | TimeoutException e) - 要求:这些异常类型互不继承(编译器会校验),且你确实对它们做同一件事——比如统一记录告警日志 + 返回错误码 500
- 注意:
e是 final,静态类型为其最近公共父类(通常是Exception),不能调用子类特有方法;若真需区分,说明不该用 multi-catch
把重复动作抽成工具方法
多个 catch 块里都写 log.error("xxx", e)、metrics.inc("error.count")、notifyOps()?这不是精细,是冗余。
- 封装一个
handleServiceError(String context, Throwable e),内部统一做上下文日志、指标上报、分级通知 - 各 catch 块里只留差异化动作:比如 SQL 异常触发事务回滚,IO 异常尝试重试,空指针则补参数校验提示
- 这样主流程干净,异常响应又不失针对性
资源清理交给 try-with-resources,别塞进 finally
多 catch 容易让人顺手把 close() 塞进每个块或 finally 里,结果是判空、嵌套 try、忽略关闭失败——反而更乱。
- 优先用
try (Resource r = new XxxResource()) { ... },JVM 自动调用close() - 若资源关闭本身可能抛异常(如流已关闭),它会被作为 suppressed exception 附在主异常上,可用
e.getSuppressed()查看 - 日志中建议一并输出主异常和 suppressed 异常,否则真实根因容易被掩盖
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











