1. 概述

在 Java 开发中,我们经常会遇到这样一个需求:如何将一个 int 值转换为对应的枚举(Enum)实例。Java 并不支持直接强制类型转换(casting),所以我们需要一些“曲线救国”的方式来实现。

虽然不能像 (PizzaStatus) 5 这样简单粗暴地转换,但通过合理的设计,完全可以做到类型安全且高效的映射。本文将介绍几种常见做法,从简单实现到高性能方案,帮你避开这个常见“踩坑点”。

2. 使用 Enum 的 values() 方法

Java 中每个枚举类都会自动生成一个静态的 values() 方法,它返回该枚举所有常量的数组,顺序与声明时一致。我们可以利用这一点,遍历数组查找匹配项。

先定义一个表示披萨订单状态的枚举类 PizzaStatus,每个状态关联一个“预计送达时间(分钟)”:

public enum PizzaStatus {
    ORDERED(5),
    READY(2),
    DELIVERED(0);

    private int timeToDelivery;

    PizzaStatus(int timeToDelivery) {
        this.timeToDelivery = timeToDelivery;
    }

    public int getTimeToDelivery() {
        return timeToDelivery;
    }
}

现在,如果我们有一个 int5,想得到对应的 PizzaStatus.ORDERED,可以这样写:

int timeToDeliveryForOrderedPizzaStatus = 5;
PizzaStatus pizzaOrderedStatus = null;

for (PizzaStatus pizzaStatus : PizzaStatus.values()) {
    if (pizzaStatus.getTimeToDelivery() == timeToDeliveryForOrderedPizzaStatus) {
        pizzaOrderedStatus = pizzaStatus;
        break; // ✅ 别忘了 break,否则继续循环
    }
}

assertThat(pizzaOrderedStatus).isEqualTo(PizzaStatus.ORDERED);

优点:逻辑清晰,无需额外结构。
缺点

  • 每次调用都要遍历整个枚举数组
  • 时间复杂度 O(n),性能差
  • 代码略显啰嗦

2.1 使用 Java 8 Stream 优化

用 Stream 可以让代码更简洁,函数式风格也更现代:

int timeToDeliveryForOrderedPizzaStatus = 5;

Optional<PizzaStatus> pizzaStatus = Arrays.stream(PizzaStatus.values())
    .filter(p -> p.getTimeToDelivery() == timeToDeliveryForOrderedPizzaStatus)
    .findFirst();

assertThat(pizzaStatus).hasValue(PizzaStatus.ORDERED);

优点:代码更简洁,可读性提升。
⚠️ 注意

  • 依然要遍历全部元素,性能没有本质提升
  • 返回的是 Optional<PizzaStatus>,调用方需处理空值情况(比如用 orElseThrow()

3. 使用 Map 实现 O(1) 查找

如果这个转换操作频繁发生(比如在高并发接口中),前面两种方式就显得“力不从心”了。我们可以通过 预构建一个 Map 缓存映射关系,实现常数时间查找。

思路很简单:在类加载时,把每个 timeToDelivery 和对应的 PizzaStatus 存入 Map<Integer, PizzaStatus>,后续直接查表即可。

private static final Map<Integer, PizzaStatus> timeToDeliveryToEnumValuesMapping = new HashMap<>();

static {
    for (PizzaStatus pizzaStatus : PizzaStatus.values()) {
        timeToDeliveryToEnumValuesMapping.put(
            pizzaStatus.getTimeToDelivery(),
            pizzaStatus
        );
    }
}

然后提供一个静态方法供外部调用:

public static PizzaStatus fromTimeToDelivery(int timeToDelivery) {
    return timeToDeliveryToEnumValuesMapping.get(timeToDelivery);
}

使用示例:

PizzaStatus status = PizzaStatus.fromTimeToDelivery(5);
assertThat(status).isEqualTo(PizzaStatus.ORDERED);

优点

  • 查找时间复杂度 O(1),性能极佳
  • 初始化只执行一次,后续无额外开销
  • 适合频繁调用场景

缺点

  • 需要额外内存存储 Map
  • 如果枚举值很多,Map 占用也不小

💡 最佳实践建议

  • 如果只是偶尔使用,用 Stream 版本足够
  • 如果是核心逻辑或高频调用,务必使用 Map 方案

4. 总结

方法 时间复杂度 是否推荐 适用场景
for 循环遍历 O(n) 仅用于理解原理
Java 8 Stream O(n) ⚠️ 低频调用,代码简洁优先
Map 预缓存 O(1) ✅✅✅ 高频调用,性能敏感

在实际项目中,Map 预缓存是更专业、更高效的选择。尤其在处理订单状态、支付类型、消息类型等枚举映射时,强烈建议采用这种方式。

所有示例代码已托管至 GitHub:https://github.com/javaguide/examples/tree/master/enum-casting


原始标题:Casting int to Enum in Java