Получение перечисления с помощью "valueOf" вызывает исключение RuntimeException-что использовать вместо этого?
у меня есть следующее перечисление
enum Animal implements Mammal {
CAT, DOG;
public static Mammal findMammal(final String type) {
for (Animal a : Animal.values()) {
if (a.name().equals(type)) {
return a;
}
}
}
}
я первоначально использовал Enum.valueOf(Animal.class, "DOG");
найти конкретное животное. Однако я не знал, что если совпадение не найдено, то IllegalArgumentException
бросается. Я подумал, что, возможно, null был возвращен. Так что у меня проблема. Я не хочу ловить это IllegalArgumentException
если совпадение не найдено. Я хочу иметь возможность искать все перечисления типа Mammal
и я не хочу реализовывать этот статический'findMammal
' для каждого перечислимого типа Mammal
. Итак, мой вопрос является ли, что было бы наиболее благоприятным проектным решением для реализации этого поведения? У меня будет такой код вызова:
public class Foo {
public Mammal bar(final String arg) {
Mammal m = null;
if (arg.equals("SomeValue")) {
m = Animal.findMammal("CAT");
} else if (arg.equals("AnotherValue") {
m = Human.findMammal("BILL");
}
// ... etc
}
}
как вы можете видеть, у меня есть разные типы млекопитающих - "животное", "человек", которые являются перечислениями. Я не хочу реализовывать "findMammal" для каждого перечисления млекопитающих. Я полагаю, что лучше всего просто создать класс утилиты, который принимает аргумент млекопитающего и ищет его? Может быть, есть более аккуратное решение.
7 ответов
как насчет создания HashMap<String, Mammal>
? Вам нужно сделать это только один раз...
public class Foo {
private static final Map<String, Mammal> NAME_TO_MAMMAL_MAP;
static {
NAME_TO_MAMMAL_MAP = new HashMap<String, Mammal>();
for (Human human : EnumSet.allOf(Human.class)) {
NAME_TO_MAMMAL_MAP.put(human.name(), human);
}
for (Animal animal : EnumSet.allOf(Animal.class)) {
NAME_TO_MAMMAL_MAP.put(animal.name(), animal);
}
}
public static Mammal bar(final String arg) {
return NAME_TO_MAMMAL_MAP.get(arg);
}
}
Примечания:
- возвращает
null
Если имя не существует - это не обнаружит столкновения имен
- вы можете использовать неизменяемую карту некоторого описания (например, via гуавы)
- вы можете написать метод утилиты для создания неизменяемой карты "имя-значение" для общего перечисления, а затем просто объединить карты :)
Если вы не хотите касаться каждого перечисления (понятно), метод утилиты-это путь. Я понимаю, что не хочу ловить исключение в вашем коде, ловить его в методе должно быть хорошо, хотя:
public static <T extends Enum<T>> T findEnumValue(Class<T> type, String name) {
if (name == null)
return null;
try {
return Enum.valueOf(type, name.toUpperCase());
} catch (IllegalArgumentException iae) {
return null;
}
}
вы можете использовать библиотеку guava. метки класс позволяет это:
Enums.valueOfFunction(MyEnum.class).apply(id);
Я не понимаю вопроса, но мне также нужен valueOf
возвращает null
вместо того, чтобы выбрасывать исключение, поэтому я создал этот метод утилиты:
public static <T extends Enum<T>> T valueOf(T[] values, String name)
{
for (T value : values) {
if (value.name().equals(name)) {
return value;
}
}
return null;
}
вы можете назвать это так:
Animal a = valueOf(Animal.values(), "CAT");
у вас ошибка в коде. Если вам нужно, чтобы ваша функция возвращала null, когда она ничего не находит, просто верните ее:
enum Animal implements Mammal {
CAT, DOG;
public static Mammal findMammal(final String type) {
for (Animal a : Animal.values()) {
if (a.name().equals(type)) {
return a;
}
}
return null; // this line works if nothing is found.
}
}
никакая технология не поможет, если вы сделаете ту же ошибку и забудете создать некоторое возвращаемое значение для каждого возможного случая.
ваш выбор: Enum-EnumMaps-HashMap зависит от динамики ваших данных. Перечисления, константы не могут быть созданы во время выполнения. С другой стороны, вам не нужно проверять много вещей в runtime-compiler будут делать это. И вы очень вероятно забудете что-то проверить. То, что легко удается Джону скиту, может вызвать головную боль.
если вы можете сказать
m = Animal.findMammal("CAT");
Почему ты не можешь сказать
m = Animal.CAT;
" CAT "должен будет соответствовать имени перечислений в любом случае, и в вашем примере" CAT " не является производным от параметра, но жестко закодирован.
обновление (возможно, больше к вопросу)
это немного сложно, но...
public interface Mammal{
public void doMammalStuff();
public static interface Finder{
public Mammal find(String name, Class<Enum<?>> enumType);
}
public static Finder FINDER = new Finder(){
public Mammal find(String name, Class<Enum<?>> enumType) {
return enumType.forName( name );
};
};
}
тогда вы можете позвонить
Mammal m = Mammal.FINDER.find( "CAT", Animal.class );
ваша реализация find() может выглядеть по-другому (т. е. не исключение).