java异常设计应分层明确职责、区分error/exception/runtimeexception、扁平化业务异常、提供全参数构造器并携带业务上下文。

Java异常捕获层级不是堆叠得越深越好,关键在于让每一层都承担明确职责:底层专注暴露问题本质,中间层做语义转化与上下文增强,顶层统一决策处理策略。过度分层反而模糊责任边界,增加维护成本。
明确区分Error、Exception与RuntimeException的使用场景
Error代表JVM级不可恢复问题,如OutOfMemoryError、StackOverflowError,不应捕获也不应重试,需从系统配置或代码结构层面解决。Exception分为两类:受检异常(Checked)仅保留在IO、网络初始化等强契约场景,例如自研客户端首次拉取配置超时必须由调用方决定是否重试;其余所有业务异常一律使用RuntimeException子类,避免Lambda表达式编译失败、API签名臃肿等问题。
业务异常应扁平化设计,避免深继承链
推荐采用“1个顶层+少量领域子类”的结构:顶层BusinessException封装errorCode、message、cause和context Map;子类按核心业务实体划分,如OrderNotFoundException、PaymentTimeoutException,每个类只表达一种明确失败语义。拒绝MyException、BaseException这类泛化命名,也避免为每个错误码新建异常类——用同一个BusinessException配合不同errorCode更易扩展和排查。
构造器必须支持全参数,禁止丢失关键上下文
每个自定义异常类需提供至少两个构造器:含errorCode和message的基础构造器,以及额外接收Throwable cause的完整构造器。严禁只留单参String message构造器,否则前端无法根据errorCode做差异化提示,日志中也缺失定位依据。同时,所有异常类必须实现Serializable,否则在Dubbo等跨进程调用中会反序列化失败。
抛出异常时务必携带可追溯的业务上下文
throw new BusinessException("库存不足") 是典型反模式。必须附带SKU ID、当前库存值、期望扣减量等关键字段,建议通过context Map传入:
- code: "INVENTORY_INSUFFICIENT"
- message: "商品【" + skuId + "】库存不足,当前剩余" + available + ",需扣减" + required
- context: Map.of("skuId", skuId, "available", available, "required", required)
这样线上排查时能直接定位到具体订单、SKU和操作环节,无需翻查上下游日志拼凑信息。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











