我曾经在代码里到处写满了if (status == 1),if (type.equals("A"))这样的判断。直到有一天,产品经理说要把状态“1”的含义从“已下单”改成“待支付”,我差点崩溃。从此,我学会了使用常量类和枚举来消灭“魔法值”。
1. 什么是“魔法值”(Magic Number/String)?
- 指在代码中突然出现的、未经定义的数字、字符串等。它们的存在使得代码难以理解和维护。
- 坏味道的代码:
if (order.getStatus() == 1) { // 1 是啥?2又是啥?
// 处理已支付
} else if (order.getStatus() == 2) {
// 处理已发货
}
public static final String TYPE_A = "A";
public static final String TYPE_B = "B";2. 解决方案一:常量类(Interface/Class with Constants)
- 将魔法值定义为有意义的常量。
public class OrderConstants {
public static final int STATUS_UNPAID = 1; // 未支付
public static final int STATUS_PAID = 2; // 已支付
public static final int STATUS_SHIPPED = 3; // 已发货
}
// 使用
if (order.getStatus() == OrderConstants.STATUS_PAID) {
// 逻辑清晰多了!
}优点: 简单直观。
缺点: 类型不安全。你仍然可以传一个99给setStatus方法,编译器不会报错。
3. 解决方案二:枚举(Enum)—— 更强大的选择
- 枚举不仅解决了魔法值问题,还提供了类型安全。
public enum OrderStatus {
UNPAID, PAID, SHIPPED, DELIVERED
}
public class Order {
private OrderStatus status; // 类型是OrderStatus,不是int!
// ... getter setter
}
// 使用
if (order.getStatus() == OrderStatus.PAID) {
// ...
}
// 编译器会检查,你不能传一个非法的值
// order.setStatus(99); // 编译错误!
order.setStatus(OrderStatus.SHIPPED); // 正确4. 枚举的高级用法:可以关联属性!
- 如果状态码在数据库里还是数字,枚举可以完美映射。
public enum OrderStatus {
UNPAID(1, "未支付"),
PAID(2, "已支付"),
SHIPPED(3, "已发货");
private final int code;
private final String desc;
OrderStatus(int code, String desc) {
this.code = code;
this.desc = desc;
}
// 根据code获取枚举实例
public static OrderStatus of(int code) {
for (OrderStatus status : values()) {
if (status.code == code) {
return status;
}
}
return null;
}
// ... getters
}
// 从数据库读出的code转换为枚举
OrderStatus status = OrderStatus.of(dbCode);总结:
告别魔法值,是写出可维护代码的重要一步。对于简单的选项,用常量类;对于有固定范围的、有关联属性的类型,强烈推荐使用枚举,它能带来更好的类型安全和代码提示。