Java Enum.valueOf () эффективность, когда значение не существует - PullRequest
10 голосов
/ 23 августа 2011

Что вы считаете более эффективным?

Использование '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);
    }
}

Обновление :

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

Ответы [ 7 ]

8 голосов
/ 23 августа 2011

Какое беспокойство по поводу производительности при втором подходе?Поймать подобное исключение почти ничего не стоит.Использование исключений для нормального потока управления, как правило, является плохой идеей с точки зрения проектирования, дни, когда это было соображением производительности, давно прошли.В отладчике использование исключений в качестве значительных операций управления замедлит процесс примерно в 10 раз. Но это оптимизируется JIT, и в производстве нет ощутимого влияния.

Эти цифры основаны на опыте работы соценка, которую я сделал для проекта zxing, который использует исключения для всех видов управления потоком.Когда я впервые увидел это, я был в ужасе.Я все еще думаю, что это не самый лучший дизайн, но я провел небольшое тестирование и с большой уверенностью могу сказать, что он не оказал реального влияния на производительность.И это алгоритм, который использовал исключения повсеместно для управления потоком.Ваша ситуация, когда исключение будет выдано только в исключительных обстоятельствах, не является проблемой.

Редактировать: у меня было одно или два отрицательных ответа на мой ответ, и я хочу убедиться, что ясупер ясно о том, что я говорю: я не думаю, что это хорошая идея использовать исключения для нормального потока управления.Тот факт, что производительность не является хорошим аргументом для того, чтобы не использовать исключения таким способом, не означает, что нет других, вполне обоснованных причин (таких как читаемость, тестируемость, расширяемость).В случае с OP использование исключения абсолютно необходимо, и оно определенно не вызовет каких-либо проблем с производительностью.

6 голосов
/ 30 января 2015

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

6 голосов
/ 23 августа 2011

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

private WeekDay getValidWeekDay(String day) {
    for (WeekDay weekDay : WeekDay.values()) {
        if(weekDay.toString().equals(day))
           return weekDay;
    }
    return null;
}

Если это не критичная по времени часть приложения, я бы не стал беспокоиться об этом в любом случае и просто выбрал бы наиболее читаемый подход. Я думаю, что будет использовать метод WeekDay.valueOf ().

Если вы предпочитаете не иметь дело с исключениями, то создайте Map ваших значений в пределах перечисления и фактически сделайте эквивалент valueOf () из поиска, который возвращает ноль, если он не найден.

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, когда он не найден. Этот подход просто возвращает ноль, таким образом не генерируя трассировку стека.

3 голосов
/ 24 августа 2011

Если ваш вопрос действительно об эффективности поиска среди 7 предметов, вы уже потратили на него слишком много времени. Даже самые быстрые алгоритмы поиска дают ноль или отрицательные преимущества до N> 15 или около того, кроме O (1).

2 голосов
/ 23 августа 2011

Или вы можете создать поиск значений перечисления внутри вашего перечисления при первой загрузке класса (см. Статический модификатор) и проверить с помощью 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);
}

Дайте мне знать, если вам нужно больше деталей

2 голосов
/ 23 августа 2011

Цикл не делает ничего такого, что не вызывает valueof, он имеет ту же функциональность: проверяет, является ли ваша строка допустимым enum. Как вы думаете, что вы получаете от первого варианта?

Второй вариант лучше всего:

 try {
     WeekDay weekDay = WeekDay.valueOf(day); // might throw exception
        ...
    } catch (IllegalArgumentException e) {
        throw new InvalidWeekDayException(day);
    }
2 голосов
/ 23 августа 2011

Сохраните действительные строки в 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...