Проверка, содержит ли тип enum константу с заданным именем - PullRequest
7 голосов
/ 28 июля 2011

В моем коде несколько перечислений:

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 ]

10 голосов
/ 28 июля 2011

Это должно работать:

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, отображающие имена в значения перечисления.

8 голосов
/ 28 июля 2011

Вот ваше решение:

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

Он получает все пустые значения перечисления и проверяет, имеет ли оно значение, которое имеет имя, совпадающее с параметром, который вы передали. Если это так, то он возвращает 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
3 голосов
/ 28 июля 2011

Я нашел другой вариант, который не должен ни перебирать все константы перечисления, ни выдавать исключение ... но это зависит от реализации, то есть использует недокументированные методы. Это работает для 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) (зависит от компилятора).

При первом вызове enumConstantDirectory или getEnumConstants() закрытый вспомогательный метод вызывает EnumType.values() (который реализуется компилятором). Затем результат повторно используется для последующих вызовов этих двух методов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...