异常分两类:业务异常(如输入非法、状态冲突)在service层抛businessexception,带业务码;系统异常(如db中断、网络超时)捕获后转systemexception并告警。

关键看异常背后的语义:是“用户做错了什么”,还是“系统哪里坏了”。不是靠抛在第几层、用没用 try-catch,而是看它代表的业务含义和后续应对方式。
看是否违反明确的业务规则
用户误操作引发的异常,一定对应可描述、可预期的业务约束:
- 输入不合法:邮箱格式错误、密码少于6位、年龄填了-5
- 状态不可流转:已发货订单尝试取消、冻结账号尝试登录、重复提交支付
- 资源前提不满足:余额不足扣款、库存为零下单、优惠券已过期
这类异常应在 Service 层主动抛出自定义 BusinessException(继承 RuntimeException),带业务码(如 "ORDER_STATUS_INVALID")和上下文(如 orderId、userId)。它不是程序 bug,而是业务逻辑按规则执行的正常分支。
看是否源于基础设施临时失效
系统故障类异常,指向数据库、网络、中间件等底层支撑环节的问题,与具体业务逻辑无关:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 数据库连接中断、SQL 执行超时、主键冲突(非因业务校验缺失导致)
- 调用第三方服务超时或返回 500、MQ 发送失败、Redis 连接断开
- 文件读写失败(磁盘满、权限不足)、线程池耗尽、配置加载异常
这类异常通常由框架或驱动抛出(如 SQLException、TimeoutException、IOException)。Service 层应捕获后统一包装为 SystemException(也继承 RuntimeException),保留原始 cause,并记录完整堆栈。它需要监控告警,可能触发熔断或降级。
看用户重试是否有意义
一个实用判断标准:
- 用户改个输入、换种操作就能继续 → 属于用户误操作,返回 HTTP 400 + 友好提示
- 用户刷新页面或等几秒再试大概率能成 → 属于系统故障,返回 HTTP 500 或 503 + “服务暂时不可用”
- 连开发都看不出为啥出这个错(如 NPE、ClassCastException、JSON 反序列化失败)→ 是编码疏漏,需补日志、加校验、修逻辑
分层处理不能错位
DAO 层只负责数据存取,不判断业务含义。例如 UPDATE 影响行数为 0,它只返回 false 或 0;是否构成“库存不足”,由 Service 层根据业务上下文判断并抛 BusinessExeption。而 DAO 层抛出的 SQLException,则应由 Service 层捕获后转为 SystemException —— 语义归位,职责清晰。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










