应优先继承exception或runtimeexception而非error或throwable;业务约束类异常(如权限不足)用检查型,逻辑错误类(如null id)用非受检型;需携带errorcode、requestid等结构化信息,命名体现业务语义,抛出时保留原始异常链。

Java自定义异常设计原则不是靠“算”,而是靠理解业务语义、遵循规范、兼顾可维护性。面试中考察的不是数学计算,而是你能否讲清楚为什么这么设计、在什么场景下用、以及如何避免常见错误。
明确异常类型归属:检查型还是非检查型?
这是设计起点。关键看异常是否属于调用方必须处理的业务约束:
- 如果业务规则强制要求上层响应(如支付金额超限、用户权限不足),继承 Exception,让编译器强制处理;
- 如果是参数明显错误、逻辑不该发生的场景(如传入 null 用户 ID 查询),继承 RuntimeException,避免污染正常流程;
- 绝不能继承 Error 或 Throwable 直接子类——那是系统级崩溃,业务代码无权模拟。
携带业务上下文:不止是 message
只重写 toString() 或只传字符串 message 是初级做法。合格的自定义异常应封装可结构化提取的信息:
- 添加 errorCode 字段,便于统一日志分类、监控告警或前端提示;
- 记录 timestamp 或 requestId,方便问题追踪;
- 提供带参数的构造方法,比如
new OrderValidationException("库存不足", "ERR_STOCK_001", orderId); - 避免在异常中放敏感数据(如密码、token),防止误打日志泄露。
命名与分层要体现业务意图
异常名不是技术标签,而是业务语言:
- 用 UserNotFoundException 而不是 UserServiceException ——前者说明“查不到人”,后者只说“服务出错了”;
- 按领域分包,如
com.example.order.exception.PaymentTimeoutException,避免所有异常堆在 util 包里; - 同类异常可抽象父类(如 OrderBusinessException),再派生具体子类,方便统一捕获和处理。
不破坏异常链,也不吞掉根因
抛出自定义异常时,务必保留原始异常上下文:
- 使用带 cause 参数的构造方法:
throw new BusinessException("下单失败", e);; - 不要只写
throw new BusinessException("下单失败");然后把原始异常 log 掉就完事; - catch 块里不要空 catch,更不要只写
e.printStackTrace()——这会让问题消失在日志里。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











