异常处理应分层捕获、职责分明:controller层统一响应http错误,service层处理事务与重试,dao层只转译数据异常;禁用通用catch,按类型精准捕获;异常需带上下文,用cause构造新异常;资源管理优先使用try-with-resources。

异常处理流程的逻辑清晰度,关键在于让每个环节意图明确、责任分明——不是堆砌 try-catch,而是让“谁该在哪儿响应什么错误”一目了然。
按业务层级分层捕获,避免混杂
不同层级对异常的应对能力不同:Controller 层适合统一包装成 HTTP 响应;Service 层负责事务回滚与重试决策;DAO 层只抛出或转译底层数据访问异常。若在 DAO 里直接 catch SQLException 并返回 success=false,就模糊了职责边界,也阻碍上层做差异化处理。
- Controller 层用 @ExceptionHandler 集中响应,返回结构化错误码和提示
- Service 方法声明 throws 业务异常(如 InsufficientBalanceException),不自行吞掉
- DAO 方法保持轻量,仅抛出或转译为更语义化的 DataAccessException
用具体异常替代通用捕获
catch (Exception e) 看似省事,实则抹平了错误类型差异,让后续日志分析、监控告警、前端提示都失去依据。比如 IOException 和 IllegalArgumentException 的修复路径完全不同,合并在一个 catch 块里只会增加排查成本。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- IO 操作只捕获 IOException 及其子类(如 FileNotFoundException)
- 参数校验失败抛 IllegalArgumentException,不捕获再抛 RuntimeException
- 数据库操作优先捕获 SQLException,而非笼统的 Exception
异常信息带上下文,不依赖堆栈猜原因
仅打印 e.printStackTrace() 或 log.error("出错了", e) 很难定位问题。清晰的异常流要求每层都补充必要上下文,而不是把所有信息都压到最底层堆栈里。
- 转译异常时用 cause 构造新异常,如 throw new OrderProcessException("订单 " + orderId + " 创建失败", e)
- 日志记录包含关键变量值,例如 "用户ID=1024,余额=-50,触发风控拦截"
- 避免在 finally 中抛异常覆盖主异常,影响原始错误传播
资源清理走 try-with-resources,别靠 finally 补救
手动在 finally 里 close 资源,既冗长又容易出错——比如 close 抛异常导致主异常被掩盖,或忘记判空引发 NPE。try-with-resources 不仅语法简洁,还能保证资源释放顺序和异常压制机制(suppressed exceptions),让资源管理逻辑从错误处理中彻底解耦。
- 所有实现 AutoCloseable 的资源(FileInputStream、Connection、Statement)都应放在 try 后的括号中
- 多个资源用分号分隔,JVM 自动按声明逆序关闭
- 无需显式 finally,也不用担心 close() 失败干扰主流程
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










