应使用enum而非static final int定义状态码,因其具备类型安全、不可变、可枚举、自带tostring/valueof及扩展字段能力,可杜绝魔法值、误赋值、无法遍历和序列化问题,并通过私有构造+getter+静态map实现高效反查与兜底保护。

直接用 enum,而不是用 static final int 定义状态码——这是最根本的“优雅替代”。static 修饰枚举本身没有意义(枚举类天然是 static 的),关键在于用 enum 的结构能力封装 code、message、行为等,从源头杜绝魔法值、类型错配和散落维护。
为什么 enum 天然比 static int 更适合全局状态码
传统整型常量的问题不是“不够 static”,而是缺乏约束和语义:
- 任意 int 都能赋值给 status 字段,比如
order.setStatus(999)编译通过,运行才崩溃 - 不同模块的常量容易重名或冲突(如
USER_NOT_FOUND=4001和ORDER_NOT_FOUND=4001) - 无法遍历所有合法状态,调试时打印出来只是数字,看不出含义
- 序列化/反序列化易出错,前端传 "4001",后端用
Integer.parseInt()转再 if 判断,脆弱且不可读
标准枚举结构:带 code、message 和快速反查
一个可落地的状态枚举应包含三要素:唯一编码、可读描述、高效查找。不建议每次调用都遍历 values():
- 私有构造器接收
int code和String message - 提供
getCode()和getMessage()方法 - 用
static final Map在类加载时预构建 code → enum 映射,避免重复遍历 - 必须定义兜底项(如
UNKNOWN(-1, "未知状态")),防止fromCode(999)返回 null 导致 NPE
示例:
public enum ResultCode {<br> SUCCESS(0, "成功"),<br> PARAM_ERROR(4000, "参数错误"),<br> USER_NOT_FOUND(4001, "用户不存在"),<br> UNKNOWN(-1, "未知错误");<br><br> private final int code;<br> private final String message;<br><br> ResultCode(int code, String message) {<br> this.code = code;<br> this.message = message;<br> }<br><br> public int getCode() { return code; }<br> public String getMessage() { return message; }<br><br> private static final Map<integer resultcode> CODE_MAP = Arrays.stream(values())<br> .collect(Collectors.toMap(ResultCode::getCode, Function.identity()));<br><br> public static ResultCode fromCode(int code) {<br> return CODE_MAP.getOrDefault(code, UNKNOWN);<br> }<br>}</integer>
让枚举真正“全局可用”的实用技巧
光定义还不够,要让它在各层顺畅使用:
-
Controller 层返回 JSON 时输出对象而非名称:加
@JsonFormat(shape = JsonFormat.Shape.OBJECT),Jackson 会自动序列化为{"code":0,"message":"成功"} -
MyBatis 查询结果自动映射:在
@Results中用@Result(column = "status", property = "status", javaType = ResultCode.class) -
统一异常处理中抛出枚举:自定义异常类接受
ResultCode构造,避免硬编码字符串或数字 -
前端交互友好:code 用 int,message 用中文;若需国际化,message 改为 key(如
"user.not.found"),交由 Spring MessageSource 渲染
哪些地方绝对不能做
保持枚举的纯粹性,才能长期稳定:
- 不在 enum 中写业务逻辑方法(如
isSuccess()、needRetry()),这些应抽到工具类或扩展函数里 - 不把 code 设为 long(JS 端可能丢失精度),优先用 int 或 String 类型
- 不依赖
Enum.valueOf()反查 code(它只认 name),始终用自定义的fromCode() - 不把枚举当配置中心用——状态码不该频繁增删,若需求多变(如角色、标签),该上数据库字典表











