开发者

Checking if enum type contains constant with given name

I have multiple enums in my code:

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

public enum Second { e, f, g; }

I want to have one method that checks to see if a value is present in any enum using valueOf() without writing one for each enum type. For example (this code does not run):

public 开发者_开发技巧boolean enumTypeContains(Enum e, String s) {
    try {
        e.valueOf(s);
    } catch (IllegalArgumentException iae) {
        return false;
    }
    return true;
}

Usage:

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

Any ideas on how to do something like this?


This should work:

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

You then have to call it by

enumTypeContains(First.class, "a");

I'm not sure if simply searching through the values (like in the answer from jinguy) might be faster than creating and throwing an exception, though. This will depend on how often you will get false, how many constants you have, and how long the stack trace is (e.g. how deep this is called).

If you need this often (for the same enum), it might be better to create once a HashSet or a HashMap mapping the names to the enum values.


Here is your solution:

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;
}

It gets all of the enum's vaules and checks to see if it has a value that shares a name with the parameter you passed in. If so, then it returns true, otherwise it returns false.

This has been tested and works. Test code:

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;
   }
}

Prints:

false
true
true


I found another variant which has neither to iterate all enum constants nor to throw an exception ... but it is implementation specific, i.e. uses undocumented methods. It works for Sun's JDK 1.6.0_20 (and was made by reading the source code from 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());
    }
}

If we were in the java.lang package, this could simply look like this:

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

This uses the method Class.enumConstantDirectory(), which (on first call) creates and (later only) returns a map with all the enum constants as values, their names as key. (Just such a map one could also create manually.)

This method is used internally by Enum.valueOf(Class, String), and supposedly also by EnumType.valueOf(String) (depends on compiler).

On the first call of enumConstantDirectory or getEnumConstants(), a private helper method invokes EnumType.values() (which is implemented by the compiler). The result is then reused for following calls of these two methods.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜