【问题标题】:Map enum to another enum with less amount of code in java将枚举映射到Java中代码量较少的另一个枚举
【发布时间】:2026-02-14 17:30:02
【问题描述】:

我有两个枚举类,一个是外部的,另一个是内部的。

public enum ExternalEnum
{
  EXTERNAL_CAR, EXTERNAL_VAN, EXTERNAL_BUS
}

public enum InternalEnum
{
  CAR, VAN, BUS
}

我需要将内部映射到外部,将外部映射到内部。所以我做了以下,

public class EnumMapper
{
  public ExternalEnum toExternal(InternalEnum internalEnum)
  {
    switch (internalEnum)
    {
    case BUS:
      return ExternalEnum.EXTERNAL_BUS;
    case CAR:
      return ExternalEnum.EXTERNAL_CAR;
    case VAN:
      return ExternalEnum.EXTERNAL_VAN;
    }
    return null;
  }

  public InternalEnum toInternal(ExternalEnum externalEnum)
  {
    switch (externalEnum)
    {
    case EXTERNAL_BUS:
      return InternalEnum.BUS;
    case EXTERNAL_CAR:
      return InternalEnum.CAR;
    case EXTERNAL_VAN:
      return InternalEnum.VAN;
    }
    return null;
  }
}

因此,相同类型的映射以两种方法重复。难道没有使用更少代码的好方法来实现这一点吗?

【问题讨论】:

    标签: java enums code-duplication


    【解决方案1】:

    我可以通过使用 BiMap 以更少的代码来实现这一点。

    import com.google.common.collect.EnumBiMap;
    
    public class EnumBiMapMapper
    {
      private EnumBiMap<InternalEnum, ExternalEnum> enumEnumBiMap = EnumBiMap.create(InternalEnum.class, ExternalEnum.class);
    
      public EnumBiMapMapper()
      {
        enumEnumBiMap.put(InternalEnum.BUS, ExternalEnum.EXTERNAL_BUS);
        enumEnumBiMap.put(InternalEnum.CAR, ExternalEnum.EXTERNAL_CAR);
        enumEnumBiMap.put(InternalEnum.VAN, ExternalEnum.EXTERNAL_VAN);
      }
    
      public ExternalEnum toExternal(InternalEnum internalEnum)
      {
        return enumEnumBiMap.get(internalEnum);
      }
    
      public InternalEnum toInternal(ExternalEnum externalEnum)
      {
        return enumEnumBiMap.inverse().get(externalEnum);
      }
    }
    

    【讨论】:

      【解决方案2】:

      Basil Bourque 的回答很好,但我不喜欢使用ordinal(),因为你可以很容易地旋转enum 常量并且会破坏业务逻辑。

      您几乎是正确的,请记住,enum 常量是一个普通的旧 java class 实例,它可以通过附加功能进行扩展。因此,最好将所有映射器逻辑隐藏在 enum 中。

      public enum ExternalEnum {
          EXTERNAL_CAR,
          EXTERNAL_VAN,
          EXTERNAL_BUS
      }
      
      public enum InternalEnum {
          CAR(ExternalEnum.EXTERNAL_CAR),
          VAN(ExternalEnum.EXTERNAL_VAN),
          BUS(ExternalEnum.EXTERNAL_BUS);
      
          private final ExternalEnum externalEnum;
      
          InternalEnum(ExternalEnum externalEnum) {
              this.externalEnum = externalEnum;
          }
      
          public ExternalEnum toExternal() {
              return externalEnum;
          }
      
          public static Optional<InternalEnum> parseExternal(ExternalEnum externalEnum) {
              for (InternalEnum internalEnum : values())
                  if (internalEnum.externalEnum == externalEnum)
                      return Optional.of(internalEnum);
              return Optional.empty();
          }
      }
      

      演示

      ExternalEnum externalEnum = ExternalEnum.EXTERNAL_CAR;
      Optional<InternalEnum> optInternalEnum = InternalEnum.parseExternal(externalEnum);
      
      System.out.println(externalEnum);
      System.out.println(optInternalEnum.orElse(null));
      System.out.println(optInternalEnum.map(InternalEnum::toExternal).orElse(null));
      

      另一种方法是只有Mapper

      public final class EnumMapper {
          
          private final Map<ExternalEnum, InternalEnum> MAP_EXT_INT = Map.of(
                  ExternalEnum.EXTERNAL_CAR, InternalEnum.CAR,
                  ExternalEnum.EXTERNAL_VAN, InternalEnum.VAN,
                  ExternalEnum.EXTERNAL_BUS, InternalEnum.BUS);
                  
          private final Map<InternalEnum, ExternalEnum> MAP_INT_EXT = Map.of(
                  InternalEnum.CAR, ExternalEnum.EXTERNAL_CAR,
                  InternalEnum.VAN, ExternalEnum.EXTERNAL_VAN,
                  InternalEnum.BUS, ExternalEnum.EXTERNAL_BUS);
                  
          public static ExternalEnum toExternal(InternalEnum internalEnum) {
              return MAP_INT_EXT.get(internalEnum);
          }
          
          public InternalEnum toInternal(ExternalEnum externalEnum) {
              return MAP_EXT_INT.get(externalEnum);
          }
          
          private EnumMapper() {}
      }
      
      public enum ExternalEnum {
          EXTERNAL_CAR,
          EXTERNAL_VAN,
          EXTERNAL_BUS
      }
      
      public enum InternalEnum {
          CAR,
          VAN,
          BUS;
      }
      

      【讨论】:

      • oleg.cherednik,有没有办法通过将映射保留在 java 数据结构中来处理这个问题?
      • @abo 你的意思是在Mapper 类? enum 也是一个 java 数据结构。
      • oleg.cherednik,我的意思是像将映射作为键值对保存在映射中,并在需要时获取它。
      【解决方案3】:

      tl;博士

      InternalEnum.values()[ externalEnum.ordinal() ]
      

      详情

      假设等效的枚举对象以相同的顺序声明,我们可以通过访问从调用隐式public static T[] values() 方法返回的所有枚举对象的数组从另一个枚举对象中检索一个枚举对象(参见this Question)和通过从错误命名的 Enum#ordinal 方法检索到的从零开始的索引号进行访问。

      例如,InternalEnum.values() 按声明顺序返回所有枚举对象的数组。然后我们使用数组访问器[…] 来检索与另一个枚举中其伴侣的索引号匹配的对象。

      InternalEnum internalEnum = InternalEnum.values()[ externalEnum.ordinal() ] ;
      

      反之亦然:

      ExternalEnum externalEnum = ExternalEnum.values()[ internalEnum.ordinal() ] ;
      

      这里是示例用法。额外提示:在 Java 16+ 中,我们可以在本地声明一个枚举 — 参见 JEP 395: Records

      enum ExternalEnum { EXTERNAL_CAR, EXTERNAL_VAN, EXTERNAL_BUS }
      enum InternalEnum { CAR, VAN, BUS }
      
      System.out.println(
              InternalEnum.values()[ ExternalEnum.EXTERNAL_VAN.ordinal() ]
      );
      
      System.out.println(
              ExternalEnum.values()[ InternalEnum.VAN.ordinal() ]
      );
      

      货车

      EXTERNAL_VAN

      【讨论】: