枚举用于定义固定、类型安全、可扩展的业务常量;适用于天然固定、数量有限、含义明确的值集合,如订单状态、支付方式、返回码,而非运行时可变数据。

用 enum 关键字定义业务常量,核心就三点:固定、类型安全、可扩展。它不是“多写几个 public static final”,而是把一组有明确语义的值封装成一个不可变的类型,编译器帮你兜底检查。
什么时候该用 enum 而不是普通常量?
判断标准很简单:这个值集合是否天然固定、数量有限、含义明确。
- ✅ 订单状态:待付款 / 已发货 / 已完成 —— 不会突然冒出第四个合法状态
- ✅ 支付方式:WECHAT_PAY / ALIPAY / BANK_TRANSFER —— 新增需显式修改代码,不是运行时动态拼出来的
- ✅ 接口返回码:SUCCESS(0) / PARAM_ERROR(-1) / SYSTEM_BUSY(503) —— 每个码带含义和行为,不是裸数字
- ❌ 用户昵称、订单ID、配置开关值 —— 这些是运行时可变或无限的,不适合枚举
写出干净可读的枚举结构
基础写法够用,但业务中建议一步到位,带上字段和方法:
public enum OrderStatus {
PENDING_PAYMENT(1, "待付款"),
PAID(2, "已付款"),
SHIPPED(3, "已发货"),
COMPLETED(4, "已完成"),
CANCELLED(5, "已取消");
private final int code;
private final String desc;
OrderStatus(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() { return code; }
public String getDesc() { return desc; }
}
- 枚举名首字母大写(OrderStatus),常量全大写加下划线(PENDING_PAYMENT)
- 每个常量后括号里传参,对应私有构造器,保证字段初始化不遗漏
- 字段声明为 final,避免后期被意外修改
- 不暴露字段本身,只提供 getter —— 封装性不能丢
让枚举真正参与业务逻辑
枚举不是摆设,可以承载轻量级行为:
- 加判断方法:
public boolean isFinalState() { return this == COMPLETED || this == CANCELLED; } - 支持按 code 查找:
public static OrderStatus fromCode(int code) { ... },内部用 Map 缓存提升性能 - 重写
toString()返回中文描述,日志打印更友好 - 在 switch 中使用:
switch (status) { case PAID: ... case SHIPPED: ... default: throw new IllegalArgumentException(); }—— 编译器强制你考虑所有分支
避开高频坑点
这些错误看似小,上线后容易引发空指针或逻辑错乱:
- 别依赖
ordinal()做业务判断(比如if (status.ordinal() == 2)),一旦调整顺序就失效;优先用自定义code或name() - 新增枚举值要考虑序列化兼容:旧版本反序列化新枚举会失败,建议 Jackson 配合
@JsonCreator处理未知值 - 不要在枚举里塞大量业务逻辑或可变状态(如缓存、计数器),违背“固定常量”本意,后期难测试难维护
- 避免和老式
Enumeration接口混淆 —— 它只是遍历器,和定义常量毫无关系











