java自定义异常区分系统错误和用户操作错误,关键在于继承关系(系统错误继承exception,用户错误继承runtimeexception)、抛出位置(dao层多系统错误,service/controller层多用户错误)及语义封装(系统异常重技术根因,用户异常重前端提示)。

Java 自定义异常区分系统错误和用户操作错误,核心在于继承关系、抛出时机和语义设计——不是靠名字判断,而是靠类型归属和处理策略。
看继承父类:决定是否强制处理
系统错误通常对应底层资源或环境故障(如数据库连不上、文件读取失败),应设计为受检异常(继承 Exception);用户操作错误反映业务规则不满足(如密码错误、余额不足、参数非法),应设计为运行时异常(继承 RuntimeException)。
- 继承 Exception → 编译器强制调用方处理(try-catch 或 throws),适合必须响应的外部依赖问题
- 继承 RuntimeException → 不强制捕获,适合可预判、可校验、属于业务逻辑范畴的问题
看抛出位置:区分错误来源
系统错误一般出现在与外部系统交互的边界处,比如 DAO 层调用 JDBC、Feign 调用远程服务、IO 读写文件时;用户操作错误多出现在 Service 或 Controller 层的业务校验环节。
- DAO 层抛出
DatabaseConnectionException extends RuntimeException→ 属于系统级不稳定,但通常归为非受检更合理(因多数框架已封装) - Service 层校验后抛出
UserLoginFailedException extends RuntimeException→ 明确是用户凭证问题,无需上层强制 try-catch - 文件上传方法声明 throws
FileUploadException extends Exception→ 外部存储不可靠,调用方需决定重试或提示用户重传
看封装内容:强化语义与可追溯性
两类异常都建议携带错误码、业务上下文和原始原因(cause),但侧重点不同:
- 系统异常侧重定位技术根因:如错误码
ERR_DB_TIMEOUT、附带 SQL 和连接池状态 - 用户异常侧重前端友好提示:如错误码
BIZ_USER_PASSWORD_INVALID、消息直接用于 toast 提示“密码格式不正确” - 两者都可通过构造函数传入 cause,便于日志中保留完整堆栈链路
实际命名与分包建议
避免模糊命名(如 MyException),按职责清晰划分:
-
system.exception 包下放:
NetworkUnavailableException、RedisConnectionException -
biz.exception 包下放:
UserNotExistsException、InsufficientBalanceException - 统一提供基类(如
BizException/SysException)简化子类编写,但不替代具体业务含义
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











