Java异常处理核心是精准分组与复用:子类异常优先捕获,父类兜底;Java 7+支持非继承异常合并(如IOException|SQLException);共性逻辑提取为私有方法;Spring推荐@ControllerAdvice统一处理。

Java中处理多种异常,核心是让每类异常得到恰当响应,既不遗漏也不过度合并。关键不在“能写几个catch”,而在于怎么分组、怎么复用、怎么避免遮蔽。
标准多catch结构:子类优先,父类兜底
这是最基础也最安全的写法,适用于所有Java版本,尤其适合逻辑差异明显的异常类型:
- 具体异常必须写在前面,比如ArithmeticException、NullPointerException、IllegalArgumentException
- 同级但语义不同的异常可并列,如SQLException和IOException,各自处理逻辑不同就分开写
- 通用兜底放在最后,如RuntimeException或Exception,但要谨慎使用——它不该是偷懒的默认出口
- 编译器会检查顺序,若把IOException写在FileNotFoundException前面,直接报错“already been caught”
Java 7+ 多异常合并:只合并非继承关系的同类处理
当多个异常需要完全一致的响应(比如统一记录日志+返回400),且它们互不继承,就用竖线|语法:
- ✅ 允许:IOException | SQLException(公共父类是Exception,无继承)
- ✅ 允许:IllegalArgumentException | IllegalStateException(都是RuntimeException直系子类)
- ❌ 禁止:IOException | EOFException(后者是前者子类,编译失败)
- 注意:合并后变量e的静态类型是最近公共父类,不能调用任一子类特有方法,如e.getSQLState()会编译报错
共性逻辑提取:避免重复又保留差异
多数真实场景不是“全一样”或“全不同”,而是“部分一样+部分专属”。这时别硬塞进一个catch,而是拆解职责:
立即学习“Java免费学习笔记(深入)”;
- 在各自catch块中先执行特有动作:如SQLException做事务回滚,IOException重命名临时文件
- 再统一调用私有方法:logAndCleanup(e, context),封装日志记录、资源释放、监控打点等共性操作
- 这样代码语义清晰,修改某类异常处理时不影响其他,也不会因合并导致类型信息丢失
全局异常处理器:Spring项目推荐替代手写try-catch
在Web应用中,大量Controller里堆满try-catch是反模式。Spring提供了更优雅的集中治理方式:
- 定义@ControllerAdvice类,用@ExceptionHandler标注方法,按异常类型精准拦截
- 自定义业务异常基类(如BusinessException),所有业务抛出都继承它,便于统一识别和响应格式
- 在处理器方法中注入WebRequest或HttpServletRequest,自动获取userId、traceId、请求路径等上下文,填入结构化日志
- 敏感字段(密码、token、原始SQL)必须脱敏,不能依赖e.getMessage()这种不可控输出


















