外观
03b. 枚举 (Enum)
目标:理解枚举是什么、为什么要用、在 Spring 项目中哪些地方会遇到。
如果你去看真实的 Java 后端项目,会发现大量的 enum——错误码、用户状态、订单类型、权限角色……几乎所有"固定选项"都用枚举表示。 JS 没有内置的枚举(TS 有),但你一定写过类似的东西。
1. 枚举是什么?
枚举就是一组命名的常量集合——值是固定的、有限的、不会变的。
前端类比:
- TS 的
enumconst STATUS = { ACTIVE: 'active', INACTIVE: 'inactive' } as const- 或者更粗暴的
type Status = 'active' | 'inactive'
JS/TS 写法
typescript
// TypeScript 枚举
enum OrderStatus {
PENDING = "PENDING",
PAID = "PAID",
SHIPPED = "SHIPPED",
CANCELLED = "CANCELLED",
}
// 或者常量对象
const ORDER_STATUS = {
PENDING: "PENDING",
PAID: "PAID",
} as const;Java 写法
java
public enum OrderStatus {
PENDING,
PAID,
SHIPPED,
CANCELLED
}就这么简单。每个值就是枚举类的一个实例。
2. 基本用法
2.1 声明与使用
java
public enum Color {
RED, GREEN, BLUE
}
// 使用
Color c = Color.RED;
System.out.println(c); // "RED"
System.out.println(c.name()); // "RED"(返回字符串)2.2 switch 配合枚举
这是最常见的用法:
java
public void handleOrder(OrderStatus status) {
switch (status) {
case PENDING:
System.out.println("等待支付");
break;
case PAID:
System.out.println("已支付,准备发货");
break;
case SHIPPED:
System.out.println("已发货");
break;
case CANCELLED:
System.out.println("已取消");
break;
}
}为什么比字符串好? 如果你写
"PIAD"(拼错了),编译器不会报错;但枚举OrderStatus.PIAD会直接编译报错。
2.3 遍历所有枚举值
java
for (OrderStatus status : OrderStatus.values()) {
System.out.println(status);
}
// PENDING
// PAID
// SHIPPED
// CANCELLED2.4 字符串 → 枚举
java
// 前端传 "PAID",后端转枚举
OrderStatus status = OrderStatus.valueOf("PAID");如果传了不存在的值(如
"UNKNOWN"),会抛IllegalArgumentException。
3. 带属性的枚举
Java 枚举的强大之处在于——每个枚举值可以携带数据。
3.1 错误码(最常见的场景)
java
public enum ErrorCode {
SUCCESS(200, "成功"),
NOT_FOUND(404, "资源不存在"),
FORBIDDEN(403, "没有权限"),
SERVER_ERROR(500, "服务器内部错误");
private final int code;
private final String message;
// 构造方法(自动私有,不能在外部 new)
ErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() { return code; }
public String getMessage() { return message; }
}使用:
java
ErrorCode err = ErrorCode.NOT_FOUND;
System.out.println(err.getCode()); // 404
System.out.println(err.getMessage()); // "资源不存在"前端类比:
typescriptconst ERROR_CODE = { SUCCESS: { code: 200, message: "成功" }, NOT_FOUND: { code: 404, message: "资源不存在" }, } as const;Java 的枚举就是把这种模式内建到语言里了。
3.2 用户角色
java
public enum UserRole {
ADMIN("管理员", 0),
VIP("VIP用户", 1),
NORMAL("普通用户", 2);
private final String label;
private final int level;
UserRole(String label, int level) {
this.label = label;
this.level = level;
}
public String getLabel() { return label; }
public int getLevel() { return level; }
}4. 枚举实现接口
枚举也是类,可以实现接口——这在策略模式中非常常见:
java
public interface PriceStrategy {
double calculate(double price);
}
public enum MemberType implements PriceStrategy {
NORMAL {
@Override
public double calculate(double price) {
return price; // 不打折
}
},
VIP {
@Override
public double calculate(double price) {
return price * 0.8; // 8 折
}
},
SVIP {
@Override
public double calculate(double price) {
return price * 0.6; // 6 折
}
};
}
// 使用
double finalPrice = MemberType.VIP.calculate(100.0); // 80.0前端类比:策略对象模式。
javascriptconst strategy = { NORMAL: (price) => price, VIP: (price) => price * 0.8, }; strategy['VIP'](100); // 80
5. 在 Spring 项目中的典型用法
5.1 DTO 中作为字段类型
java
public class OrderDTO {
private Long id;
private OrderStatus status; // ← 枚举类型,不是 String
// getter/setter...
}前端传 JSON { "id": 1, "status": "PAID" },Spring 会自动把 "PAID" 转成 OrderStatus.PAID。
5.2 数据库映射
MongoDB 中通常存为字符串,MySQL 中可以存为字符串或整数。ORM 框架会自动转换。
5.3 统一响应中的错误码
java
@GetMapping("/{id}")
public Result<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
if (user == null) {
return Result.fail(ErrorCode.NOT_FOUND);
}
return Result.ok(user);
}总结
- 枚举 = 一组命名的常量。 比字符串安全(编译期检查)、比数字可读。
- 带属性的枚举可以携带 code、message 等额外信息——非常适合做错误码、状态码。
- 枚举可以实现接口——用来做策略模式,替代一堆 if-else。
- 在真实项目中,状态码、错误码、角色类型、业务类型基本都是枚举。
- Spring 会自动把前端传来的字符串转成枚举值。
