精准拦截异常的关键在于分层处理:业务异常友好提示不记error日志,系统异常记录堆栈并监控,通用异常必须告警且兜底500响应;需用@controlleradvice结构化分发,避免万能catch,合并捕获仅限无继承关系且响应一致的异常,共性逻辑应抽离复用。

精准拦截处理异常,关键不在“捕获得多”,而在于分得清、理得顺、响应得当。核心是让每类异常走它该走的路:业务问题给用户明确提示,系统故障留足排查线索,通用错误不被吞掉也不乱报。
按语义分层:业务异常、系统异常、通用异常三类隔离
不同来源的异常,处理目标完全不同:
-
业务异常(如
InsufficientBalanceException、CouponExpiredException):属于正常流程分支,不记ERROR日志,返回友好提示码和消息,前端可直接展示 -
系统异常(如
SQLException、RedisConnectionException):反映外部依赖或基础设施问题,需记录完整堆栈、打监控点,返回统一服务降级提示(如“当前服务繁忙,请稍后再试”) -
通用异常(如
NullPointerException、ArrayIndexOutOfBoundsException):多由编码疏漏引起,必须记ERROR日志并告警,但对外仍要兜底为500类响应,避免暴露内部细节
用@ControllerAdvice做全局拦截,但别全扔给一个catch
@ControllerAdvice不是“万能兜底筐”,而是结构化分发的中枢:
- 为每类异常写独立的
@ExceptionHandler方法,比如专门处理BusinessException、IOException、RuntimeException - 同一个异常类型下,若需差异化响应(如不同HTTP状态码),可通过子类区分,而不是在方法里if-else判断消息内容
- 最末尾的
@ExceptionHandler(Exception.class)仅作保底,只做日志+统一封装,不包含业务逻辑
合并处理要谨慎:只合并非继承关系且响应完全一致的异常
Java 7+支持catch (IOException | SQLException e),但有严格前提:
- 两个异常类不能有父子继承关系(
EOFException是IOException子类,禁止合并) - 合并后变量
e的类型是它们最近公共父类(如Exception),无法调用任一子类特有方法 - 仅适用于“纯日志+统一返回”的场景;若需回滚事务或重命名文件等专属动作,必须拆开写独立catch
共性逻辑抽离:用私有方法封装日志、清理、监控
避免在每个catch里重复写log.error("xxx", e)或closeResource():
- 定义私有方法如
logAndNotify(Throwable e, String context),集中处理日志级别、告警开关、上下文埋点 - 在各catch块中先执行差异化操作(如
rollbackTx()),再调用该共性方法 - 这样既保持处理路径清晰,又确保关键动作不遗漏、不散落
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











