Java异常设计需分层明确、catch由细到粗、避免异常滥用:自定义异常应继承BusinessException形成模块化层级,禁止混用检查/非检查异常,方法只声明真实可能抛出的异常,高频业务状态应封装为Result而非异常。

Java中合理设计异常结构,关键在于让多catch语句能清晰区分不同错误场景,避免捕获过于宽泛或重叠的异常类型。
继承体系要层次分明
自定义异常应基于业务语义构建层级关系,而非简单堆砌。例如,统一继承BusinessException,再按模块或错误性质细分:订单异常(OrderException)、支付异常(PaymentException),两者都继承自BusinessException,但互不继承。这样在catch块中可分别处理,又可通过父类统一兜底。
- 避免让多个自定义异常直接继承RuntimeException——它们之间无继承关系,多catch无法体现优先级
- 检查异常(Exception子类)与非检查异常(RuntimeException子类)不应混在同一继承链底层,否则编译器无法正确推导catch顺序
- 若需共用错误码或上下文,提取为接口(如ErrorCodeAware),而非强行拉平继承
方法声明要精准抛出
在方法签名中只声明该方法真正可能抛出的异常类型,不“打包”声明父类或无关异常。这直接影响调用方能否写出有意义的多catch逻辑。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 例如processOrder()只throws InsufficientBalanceException和InventoryShortageException,而不是笼统throws BusinessException
- 工具类或底层方法若封装了多种异常,应在内部完成转换,对外暴露语义明确的异常,而非把原始异常(如SQLException、IOException)直接往上抛
- 使用throws声明时,确保其与实际throw语句一致,IDE和编译器会据此校验catch的合法性
catch顺序必须由细到粗
多catch块的排列不是随意的,JVM按代码顺序匹配第一个能接收该异常实例的catch。因此具体异常必须写在通用异常之前。
立即学习“Java免费学习笔记(深入)”;
- 正确写法:catch (InventoryShortageException e) → catch (OrderException e) → catch (BusinessException e)
- 若把BusinessException放在前面,后面更具体的异常永远无法被捕获,编译器会报错“unreachable catch block”
- 同一层级的并列异常(如PaymentTimeoutException和PaymentRejectedException)可任意顺序,但建议按常见程度或处理优先级排列
避免用异常传递业务状态
异常用于处理“意外”,不是控制流手段。若大量使用异常来表示可预期的业务分支(如“用户未登录”、“参数校验失败”),会导致多catch逻辑膨胀、难以维护,且掩盖真实错误。
- 将高频、可预判的业务结果封装为返回对象(如Result
或Optional),仅对真正异常情况抛异常 - 即使使用异常,也应保证每个catch块有明确职责:记录日志、回滚事务、转换为HTTP状态码等,而非重复做条件判断
- 不要为了适配多catch而人为制造异常类型——比如为每个HTTP状态码定义一个异常,反而破坏抽象一致性

















