【问题标题】:Can I get an enum based on the value of its field?我可以根据其字段的值获取枚举吗?
【发布时间】:2013-03-12 19:23:34
【问题描述】:

我想根据其字段值获取特定的枚举。

枚举:

public enum CrimeCategory {
    ASBO ("Anti Social Behaviour"),
    BURG ("Burglary"),
    CRIMDAM ("Criminal Damage And Arson"),
    DRUGS ("Drugs"),
    OTHTHEFT ("Other Theft"),
    PUPDISOR ("Public Disorder And Weapons"),
    ROBBERY ("Robbery"),
    SHOPLIF ("Shoplifting"),
    VEHICLE ("Vehicle Crime"),
    VIOLENT ("Violent Crime"),
    OTHER ("Other Crime");

    private  String category;


    private CrimeCategory (String category) {
        this.category = category;
    }

    public String returnString() {
        return category; 
    }
}


获取新枚举:

aStringRecivedFromJson = "Anti Social Behaviour"
CrimeCategory crimeCategoryEnum;
crimeCategoryEnum = CrimeCategory.valueOf(aStringRecivedFromJson); 

我一直在尝试找到一种方法,将上述方法带回一个枚举,以便可以将其与其他 Crime 信息一起存储在 HashMap 中。

预期结果:ASBO

【问题讨论】:

  • toString() 会给你一个枚举的字符串表示,除非你覆盖它。
  • @Jethro 仅供参考,您并没有真正使用该示例代码“初始化新枚举”。事实上,你不能这样做,因为 Java 中的枚举实际上是单例。您实际上是在查找现有的枚举值。

标签: java string enums


【解决方案1】:

作为参考,这里有一个 HashMap 的替代解决方案:

enum CrimeCategory {
  ASBO("Anti Social Behaviour"),
  BURG("Burglary"),
  CRIMDAM("Criminal Damage And Arson"),
  DRUGS("Drugs"),
  OTHTHEFT("Other Theft"),
  PUPDISOR("Public Disorder And Weapons"),
  ROBBERY("Robbery"),
  SHOPLIF("Shoplifting"),
  VEHICLE("Vehicle Crime"),
  VIOLENT("Violent Crime"),
  OTHER("Other Crime");

  private static final Map<String, CrimeCategory> map = new HashMap<>(values().length, 1);

  static {
    for (CrimeCategory c : values()) map.put(c.category, c);
  }

  private final String category;

  private CrimeCategory(String category) {
    this.category = category;
  }

  public static CrimeCategory of(String name) {
    CrimeCategory result = map.get(name);
    if (result == null) {
      throw new IllegalArgumentException("Invalid category name: " + name);
    }
    return result;
  }
}

【讨论】:

  • 非常感谢您,如果更频繁地调用类别值,我将合并HashMap。目前它仅在单击地图标记时调用,因此性能目前还可以
【解决方案2】:

CrimeCategory枚举添加一个静态方法:

public static CrimeCategory valueOf(String name) {
    for (CrimeCategory category : values()) {
        if (category.category.equals(name)) {
            return category;
        }
    }    
    throw new IllegalArgumentException(name);
}

【讨论】:

  • 或者如果性能很关键,可以使用包含映射的静态 HashMap...
  • 确实......我不确定实际的枚举值是在静态初始化块运行之前还是之后创建的,所以我想我会保持简单。
  • @sharakan 是的,从枚举构造函数到 Mapenum 的静态字段)的自注册将 NPE。 (解决方案:将静态放在嵌套类中或在静态初始化程序中循环 value() 将它们放入地图中。)
  • @sharakan 请参阅我的答案以获得 HashMap 的替代方案 - 除非它经常被调用,否则可能不值得。
  • @sharakan 非常感谢您提供此代码。工作完美。我四处寻找几个小时试图找到解决方案:)
【解决方案3】:

基于实例字段的值返回枚举常量的静态工厂方法采用其他答案中描述的两种形式之一:基于迭代枚举值的解决方案,或基于HashMap 的解决方案.

对于常量数量较少的枚举,迭代解决方案的性能应该与HashMap 解决方案一样(需要计算哈希码,将其与存储桶匹配,并假设不会发生哈希冲突) .

对于较大的枚举,基于映射的解决方案性能更高(但需要内存中的存储空间)。但是,如果不经常调用工厂方法,那么使用映射对整体性能的提升可能仍然非常小。

对静态工厂方法使用迭代查找还是基于映射的查找的总体决定最终取决于您的要求和环境。从迭代查找开始,然后在分析显示实际性能问题时更改为基于映射的实现永远不会错。

最后,从 Java 8 开始,Streams API 支持基于管道的映射解决方案(其性能应该类似于迭代解决方案)。例如,假设您想创建一个接口,您可以在任何枚举类上使用该接口来表达您的意图,即它应该可以通过其实例字段之一进行匹配。我们称这个接口为Matchable。该接口定义了一个方法,该方法返回您要匹配的实例字段(例如getField())。这个接口还可以定义一个静态工厂方法来从任何实现的枚举类中返回一个常量:

interface Matchable {

    Object getField();

    public static <E extends Enum<E> & Matchable> E forToken(Class<E> cls, Object token) {

        return Stream.of(cls.getEnumConstants())
            .filter(e -> e.getField().equals(token))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("Unknown token '" +
                    token + "' for enum " + cls.getName()));
    }
}

现在,您定义的任何实现Matchable 的枚举类都可以使用Matchable.forToken() 静态工厂方法来查找其实例字段值与提供的参数匹配的枚举常量。

泛型类型声明E extends Enum&lt;E&gt; &amp; Matchable 确保作为参数传递给方法的类型标记将用于实现Matchable 的枚举类(否则代码将无法编译)。

【讨论】:

    【解决方案4】:

    Assylias 的回答很棒。虽然我会从工厂方法返回一个Optional,让客户端处理找不到枚举的情况(当然,如果你在内部使用这个枚举并且你认为调用这个方法时抛出IllegalArgumentException可能会更好永远不会发生错误的论点——这是你的选择)。

    而且我还会将Map 包装到不可修改的包装器中,以免在您的枚举中意外修改它(Map 是私有的,但稍后有人可以在添加新功能时对其进行修改 - 它至少会强制思考关于它):

    enum CrimeCategory {
        ASBO("Anti Social Behaviour"),
        BURG("Burglary"),
        CRIMDAM("Criminal Damage And Arson"),
        DRUGS("Drugs"),
        OTHTHEFT("Other Theft"),
        PUPDISOR("Public Disorder And Weapons"),
        ROBBERY("Robbery"),
        SHOPLIF("Shoplifting"),
        VEHICLE("Vehicle Crime"),
        VIOLENT("Violent Crime"),
        OTHER("Other Crime");
    
        private static final Map<String, CrimeCategory> MAP;
    
        static {
             Map<String, CrimeCategory> crimeCategoryMap = Arrays.stream(values())
                    .collect(toMap(cg -> cg.category, e -> e));
             MAP = Collections.unmodifiableMap(crimeCategoryMap);
        }
    
        private final String category;
    
        private CrimeCategory(String category) {
            this.category = category;
        }
    
        public static Optional<CrimeCategory> of(final String name) {
            return Optional.ofNullable(MAP.get(name));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-15
      • 1970-01-01
      • 2012-03-18
      相关资源
      最近更新 更多