Я смотрел под капотом для EnumSet.allOf
и это выглядит очень эффективным, специально для перечислений меньше чем с 64 значениями.
В основном все наборы совместно используют единый массив всех возможных перечислимых значений, и единственная другая информация является битовой маской который в случае allOf
установлен в одном налете.
С другой стороны, Enum.values (), кажется, немного черной магии. Кроме того, это возвращает массив, не набор, так во многих случаях это должно быть украшено Arrays.asList (), чтобы быть применимым в любом месте, которое ожидает набор.
Так, должен EnumSet.allOf
будьте более предпочтительны для Enum.values
?
Строго говоря, который форма for
итератор должен использоваться:
for ( final MyEnum val: MyEnum.values( ) );
или
for ( final MyEnum val: EnumSet.allOf( MyEnum.class ) );
Поскольку я не получил ответа на свой вопрос, какой из них более эффективен, я решил провести собственное тестирование.
Я тестировал итерацию по values ()
, Arrays.asList (values ())
и EnumSet.allOf ()
. {{1} } Я повторил эти тесты 10 000 000 раз для разных размеров перечислений. Вот результаты тестов:
oneValueEnum_testValues 1.328
oneValueEnum_testList 1.687
oneValueEnum_testEnumSet 0.578
TwoValuesEnum_testValues 1.360
TwoValuesEnum_testList 1.906
TwoValuesEnum_testEnumSet 0.797
ThreeValuesEnum_testValues 1.343
ThreeValuesEnum_testList 2.141
ThreeValuesEnum_testEnumSet 1.000
FourValuesEnum_testValues 1.375
FourValuesEnum_testList 2.359
FourValuesEnum_testEnumSet 1.219
TenValuesEnum_testValues 1.453
TenValuesEnum_testList 3.531
TenValuesEnum_testEnumSet 2.485
TwentyValuesEnum_testValues 1.656
TwentyValuesEnum_testList 5.578
TwentyValuesEnum_testEnumSet 4.750
FortyValuesEnum_testValues 2.016
FortyValuesEnum_testList 9.703
FortyValuesEnum_testEnumSet 9.266
Это результаты тестов, запускаемых из командной строки. Когда я запускал эти тесты из Eclipse, я получил огромную поддержку testValues
. В основном это было меньше, чем EnumSet
даже для небольших перечислений. Я считаю, что прирост производительности достигается за счет оптимизации итератора массива в цикле for (val: array)
.
С другой стороны, как только вам понадобится java.util.Коллекция для передачи, Arrays.asList ()
уступает место EnumSet.allOf
, особенно для небольших перечислений, которые, как я полагаю, будут большинством в любой данной кодовой базе.
Итак, я бы сказал, что вам следует использовать
for ( final MyEnum val: MyEnum.values( ) )
, но
Iterables.filter(
EnumSet.allOf( MyEnum.class ),
new Predicate< MyEnum >( ) {...}
)
И использовать только Arrays.asList (MyEnum.values ())
, где java.util.List
- абсолютно необходимо.
Есть также Class.getEnumConstants ()
под капотом, все они вызывают values ()
методы перечисления в любом случае типы через отражение .
Вы должны использовать тот подход, который для вас наиболее прост и понятен. В большинстве ситуаций производительность не должна быть важным фактором.
ИМХО: ни один из вариантов не работает очень хорошо, поскольку оба они создают объекты. Один в первом случае и три во втором. Для повышения производительности можно создать константу, которая будет хранить все значения.
Не то чтобы я прошел через всю реализацию, но мне кажется, что EnumSet.allOf () в основном использует ту же инфраструктуру, что и .values (). Поэтому я ожидаю, что EnumSet.allOf () потребует некоторых (возможно, незначительных) дополнительных шагов (см. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6276988 ).
Мне кажется очевидным, что предполагаемое использование foreach - для (MyEnum val: MyEnum.values ())
почему это делается по-другому? Вы только запутаете программиста обслуживания.
Я имею в виду, что если вам нужна коллекция, вы должны ее получить. Если вы хотите использовать foreach, достаточно массивов. Я бы даже предпочел массивы при нажатии! Зачем что-то оборачивать, если то, что у вас есть (массив), достаточно хорошо? Простые вещи обычно быстрее.
В любом случае, Питер Лори прав. Не беспокойтесь о производительности этого ... Это достаточно быстро, и есть вероятность, что есть миллион других узких мест, которые делают эту крошечную теоретическую разницу в производительности совершенно несущественной (хотя не смотрите его точку зрения о "создании объекта". Для меня первое пример кажется на 100% нормальным).
Метод values ()
более понятен и эффективен, если вы просто хотите перебрать все возможные значения перечисления. Значения кэшируются классом (см. Class.getEnumConstants ()
)
Если вам нужно подмножество значений, вы должны использовать EnumSet
. Начните с allOf ()
или noneOf ()
и добавьте или удалите значения или используйте только of ()
по мере необходимости.