Java Enum.valueOf() эффективность, когда значение не существует
Что вы считаете более эффективным?
Использование "WeekDay" является всего лишь примером:
public enum WeekDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY;
}
Сначала прокрутите и проверьте строку дня:
public void parseString(String line) {
String[] tokens = line.split();
String day = tokens[1]; // day 'should' always be a weekday
if (isValidWeekDay(day)) {
WeekDay weekDay = WeekDay.valueOf(day); // won't throw exception
...
} else {
throw new InvalidWeekDayException(day); // subclass of RuntimeException
}
}
private boolean isValidWeekDay(String day) {
for (WeekDay weekDay : WeekDay.values()) {
if(weekDay.toString().equals(day))
return true;
}
return false;
}
Или, поскольку в 99,99% случаев день будет правильным:
public void parseString(String line) {
String[] tokens = line.split();
String day = tokens[1]; // day 'should' always be a weekday
try {
WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
...
} catch (IllegalArgumentException e) {
throw new InvalidWeekDayException(day, e);
}
}
Обновить:
Чтобы уточнить, входная строка будет поступать из клиентского приложения, а не из пользователя. Другими словами, в этом примере было бы ошибкой получить нерабочий день.
Ответы
Ответ 1
Я знаю его старый пост, но я считаю, что следующий результат будет интересен. Я запускаю 10000000 тестов, чтобы найти элемент в enum ENUM {FIRST, SECOND, THIRD, FOURTH, LAST}
с помощью JDK 1.8. В приведенной ниже таблице указано время, требуемое простым циклом и valueOf()
.
text loop valueOf ratio
------------------------------
"FIRST" 121 65 186%
"LAST" 188 57 330%
"foo" 155 8958 1.7%
Заключение. Я бы не использовал valueOf()
, если я ожидаю, что значения не соответствуют перечислению.
Ответ 2
Какова проблема производительности в отношении второго подхода? Захват такого исключения стоит почти ничего. Использование исключений для нормального потока управления, как правило, является плохой идеей с точки зрения дизайна, дни, когда это было соображение эффективности, давно прошли. В отладчике использование исключений в качестве значимых управляющих операций замедляет работу примерно в 10 раз. Но это оптимизируется JIT, и в производстве нет заметного влияния.
Эти цифры основаны на опыте с оценкой, которую я сделал в проекте zxing, который использует исключения для всех видов управления потоком. Когда я впервые увидел это, я был в ужасе. Я все еще думаю, что это не лучший дизайн, но я провел довольно много испытаний и могу с большой долей уверенности сказать, что это не оказало реального влияния на производительность. И это алгоритм, который использует исключения для управления потоком. Ваша ситуация, когда исключение попадает только в исключительных обстоятельствах, не является проблемой.
Изменить: у меня на моем ответе был второй или второй вопрос, и я хочу убедиться, что я очень четко понимаю, что я говорю: я не думаю, что это хорошая идея использовать исключения для нормального контроль потока. Просто потому, что производительность не является хорошим аргументом в пользу исключения исключений, этот способ не означает, что нет других, вполне обоснованных причин (таких как читаемость, тестируемость, расширяемость). В случае OP, использование исключения абсолютно вызвано и, безусловно, не вызовет каких-либо проблем с производительностью.
Ответ 3
Как уже было прокомментировано, вам нужно будет профиль, чтобы узнать наверняка. Даже в вашем собственном синтаксическом подходе вы можете сделать это быстрее, возвращая перечисление при анализе списка.
private WeekDay getValidWeekDay(String day) {
for (WeekDay weekDay : WeekDay.values()) {
if(weekDay.toString().equals(day))
return weekDay;
}
return null;
}
Если это не критическая часть приложения, я бы не стал беспокоиться об этом в любом случае и просто взять наиболее читаемый подход. Я думаю, что будет использовать метод WeekDay.valueOf().
Если вам не нужно иметь дело с исключениями, тогда создайте карту своих значений в enum и эффективно выполните эквивалент valueOf() из поиска, который возвращает null, если он не найден.
public enum WeekDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY;
private static Map<String, WeekDay> valueMap;
public static WeekDay getValue(String possibleName)
{
if (valueMap == null)
{
valueMap = new HashMap<String, WeekDay>();
for(WeedDay day: values())
valueMap.put(day.toString(), day);
}
return valueMap.get(possibleName);
}
}
Это эффективно то, что делает метод valueOf(), но это исключает исключение IllegalArgumentException, когда оно не найдено. Этот подход просто возвращает значение null, поэтому не генерирует stacktrace.
Ответ 4
Если ваш вопрос действительно об эффективности поиска среди 7 пунктов, вы уже потратили слишком много времени на него. Даже самые быстрые алгоритмы поиска дают нулевые или отрицательные преимущества до N > 15 или около того, кроме O (1).
Ответ 5
Сохраните допустимые строки в HashSet
и определите, является ли строка действительным днем или нет на основе Set.contains(...)
.
Набор может быть static final Set
, и вы можете обернуть его немодифицируемым для хорошей меры:
private static final Map<String> WEEKDAY_STRINGS;
static {
HashSet<String> set = new HashSet();
for (WeekDay d : WeekDay.values()) {
set.add(d.toString());
}
WEEKDAY_STRINGS = Collections.unmodifiableSet(set);
}
Ответ 6
Цикл не делает ничего, что вызывающий valueof не имеет, они имеют одинаковую функциональность: проверка правильности строки. Как вы думаете, что вы получаете от первого варианта?
Второй вариант лучше:
try {
WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
...
} catch (IllegalArgumentException e) {
throw new InvalidWeekDayException(day);
}
Ответ 7
Или вы можете создать поиск значений enum внутри вашего перечисления при первом загрузке класса (см. статический модификатор) и выполнить проверку с помощью get(), как показано ниже:
private String dayName;
private static final Map<String,Weekday> lookup = new HashMap<String, Weekday>();
static{
for (Weekday day: values()){
lookup.put(day.dayName, d);
}
}
public static Weekday get(String _name){
return lookup.get(_name);
}
Сообщите мне, если вам нужна дополнительная информация