检查枚举类型是否包含给定名称的常量

时间:2011-07-27 20:12:34

标签: java generics enums

我的代码中有多个枚举:

public enum First { a, b, c, d; }

public enum Second { e, f, g; }

我想有一个方法,使用valueOf()检查任何枚举中是否存在值,而不为每个枚举类型写一个值。例如(此代码不运行):

public boolean enumTypeContains(Enum e, String s) {
    try {
        e.valueOf(s);
    } catch (IllegalArgumentException iae) {
        return false;
    }
    return true;
}

用法:

enumTypeContains(First,"a"); // returns true
enumTypeContains(Second,"b"); // returns false

关于如何做这样的事情的任何想法?

3 个答案:

答案 0 :(得分:10)

这应该有效:

public <E extends Enum<E>> boolean enumTypeContains(Class<E> e, String s) {
    try {
        Enum.valueOf(e, s);
        return true;
    }
    catch(IllegalArgumentException ex) {
        return false;
    }
}

然后你必须通过

来调用它
enumTypeContains(First.class, "a");

我不确定是否只是简单地搜索这些值(比如来自jinguy的答案)可能比创建和抛出异常更快。这将取决于您获得false的频率,您拥有的常数以及堆栈跟踪的持续时间(例如,调用的深度)。

如果您经常需要(对于相同的枚举),最好创建一次HashSet或HashMap将名称映射到枚举值。

答案 1 :(得分:8)

以下是您的解决方案:

public static boolean contains(Class<? extends Enum> clazz, String val) {
   Object[] arr = clazz.getEnumConstants();
   for (Object e : arr) {
      if (((Enum) e).name().equals(val)) {
         return true;
      }
   }
   return false;
}

它获取所有enum的vaules并检查它是否具有与您传入的参数共享名称的值。如果是,则返回true,否则返回false。

这已经过测试并且有效。测试代码:

public class Test {
   public static void main(String[] args) {
      System.out.println(contains(Haha.class, "Bad"));
      System.out.println(contains(Haha.class, "Happy"));
      System.out.println(contains(Haha.class, "Sad"));
   }

   static enum Haha {
      Happy, Sad;
   }
}

打印:

false
true
true

答案 2 :(得分:3)

我找到了另一个变体,既不迭代所有枚举常量也不抛出异常......但它是特定于实现的,即使用未记录的方法。它适用于Sun的JDK 1.6.0_20(并且是通过阅读1.6.0_13中的源代码制作的。)

public static <E extends Enum<E>> boolean enumTypeContains(Class<E> e, String s) {
    try {
        Method enumDir = Class.class.getDeclaredMethod("enumConstantDirectory");
        enumDir.setAccessible(true);
        Map<?,?> dir = (Map<?,?>)enumDir.invoke(e);
        return dir.containsKey(s);
    }
    catch(NoSuchMethodException ex) {
        throw new Error(ex);
    }
    catch(IllegalAccessException ex) {
        throw new Error(ex);
    }
    catch(InvocationTargetException ex) {
        throw new Error(ex.getCause());
    }
}

如果我们在java.lang包中,这可能看起来像这样:

public static <E extends Enum<E>> boolean enumTypeContains(Class<E> e, String s) {
    return e.enumConstantDirectory().containsKey(s);
}

这使用方法Class.enumConstantDirectory(),它(在第一次调用时)创建并且(稍后仅)返回一个包含所有枚举常量作为值的映射,它们的名称作为键。 (只有这样的地图也可以手动创建。)

此方法由Enum.valueOf(Class, String)在内部使用,也可能由EnumType.valueOf(String)使用(取决于编译器)。

enumConstantDirectorygetEnumConstants()的第一次调用中,私有帮助器方法调用EnumType.values()(由编译器实现)。然后将结果重用于以下两种方法的调用。