应为每个异常场景绑定全局唯一、可读性强、结构化的异常id,采用“模块_动词_资源_原因”大写下划线格式,如system_null_pointer_user_id,并通过中心化配置映射到错误码与提示,配合ci校验与文档治理保障唯一性。

System 类方法抛出的异常若只依赖默认消息或简单码值,容易在多模块、多团队协作中出现错误码重复、含义模糊、难以追溯的问题。解决核心是:为每个异常场景绑定全局唯一、可读性强、结构化的异常 ID,再通过统一的异常处理机制映射到具体错误码与提示。
设计唯一异常 ID 的命名规则
异常 ID 不是随机字符串,而是带语义的标识符,建议采用 模块_动词_资源_原因 格式,全部大写加下划线,确保全局唯一且可检索:
- SYSTEM_NULL_POINTER_USER_ID —— System 类中因用户 ID 为空触发空指针
- SYSTEM_IO_TIMEOUT_FILE_READ —— 文件读取超时(非泛化 IOException)
- SYSTEM_PERMISSION_DENIED_ENV_VAR —— 访问系统环境变量被拒绝
避免使用数字编号(如 ERR_1001)、模糊词(如 GENERAL_ERROR)或含版本/时间戳(易过期难维护)。
在 System 方法中主动抛出带 ID 的异常
不直接 throw new RuntimeException("xxx"),而是封装一层异常工厂:
- 定义统一异常基类(如 SystemException),构造时强制传入异常 ID 字符串
- 提供静态快捷方法:SystemException.of("SYSTEM_IO_TIMEOUT_FILE_READ")
- System 类内部方法调用时,捕获底层异常后包装重抛:
throw SystemException.of("SYSTEM_IO_TIMEOUT_FILE_READ").withCause(e);
建立异常 ID 到错误码与文案的中心化映射
所有异常 ID 必须注册到一个不可变配置源(如 classpath 下的 system-error-codes.yaml),内容示例:
SYSTEM_NULL_POINTER_USER_ID: code: 500201 message: "用户标识缺失,无法执行系统操作" level: ERROR SYSTEM_IO_TIMEOUT_FILE_READ: code: 500317 message: "读取系统配置文件超时,请检查磁盘与权限" level: WARN
运行时由统一异常处理器(如 Spring 的 @ControllerAdvice)根据异常 ID 查表,返回标准化的响应体(含 code + message + traceId),彻底隔离业务逻辑与错误呈现。
配套治理机制防止冲突与退化
仅靠约定无法长期保障唯一性,需工程化卡点:
- CI 阶段扫描所有 SystemException.of("XXX") 调用,校验 ID 是否存在于配置文件,缺失则构建失败
- Git 提交前钩子(pre-commit)检查新增 ID 是否已存在,禁止重复
- 内部文档站自动聚合所有 ID,支持按模块/关键词搜索,并标注首次引入位置和责任人
这样,每个 System 层异常都具备可定位、可统计、可演进的“身份证”,错误码冲突自然消失。










