Enum.values () по сравнению с EnumSet.allOf (). Какой более предпочтителен?

Я смотрел под капотом для 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 ) );
57
задан blazeroni 11 October 2012 в 00:45
поделиться

5 ответов

Поскольку я не получил ответа на свой вопрос, какой из них более эффективен, я решил провести собственное тестирование.

Я тестировал итерацию по 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 - абсолютно необходимо.

89
ответ дан 24 November 2019 в 19:31
поделиться

Есть также Class.getEnumConstants ()

под капотом, все они вызывают values ​​() методы перечисления в любом случае типы через отражение .

7
ответ дан 24 November 2019 в 19:31
поделиться

Вы должны использовать тот подход, который для вас наиболее прост и понятен. В большинстве ситуаций производительность не должна быть важным фактором.

ИМХО: ни один из вариантов не работает очень хорошо, поскольку оба они создают объекты. Один в первом случае и три во втором. Для повышения производительности можно создать константу, которая будет хранить все значения.

12
ответ дан 24 November 2019 в 19:31
поделиться

Не то чтобы я прошел через всю реализацию, но мне кажется, что EnumSet.allOf () в основном использует ту же инфраструктуру, что и .values ​​(). Поэтому я ожидаю, что EnumSet.allOf () потребует некоторых (возможно, незначительных) дополнительных шагов (см. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6276988 ).

Мне кажется очевидным, что предполагаемое использование foreach - для (MyEnum val: MyEnum.values ​​()) почему это делается по-другому? Вы только запутаете программиста обслуживания.

Я имею в виду, что если вам нужна коллекция, вы должны ее получить. Если вы хотите использовать foreach, достаточно массивов. Я бы даже предпочел массивы при нажатии! Зачем что-то оборачивать, если то, что у вас есть (массив), достаточно хорошо? Простые вещи обычно быстрее.

В любом случае, Питер Лори прав. Не беспокойтесь о производительности этого ... Это достаточно быстро, и есть вероятность, что есть миллион других узких мест, которые делают эту крошечную теоретическую разницу в производительности совершенно несущественной (хотя не смотрите его точку зрения о "создании объекта". Для меня первое пример кажется на 100% нормальным).

2
ответ дан 24 November 2019 в 19:31
поделиться

Метод values ​​() более понятен и эффективен, если вы просто хотите перебрать все возможные значения перечисления. Значения кэшируются классом (см. Class.getEnumConstants () )

Если вам нужно подмножество значений, вы должны использовать EnumSet . Начните с allOf () или noneOf () и добавьте или удалите значения или используйте только of () по мере необходимости.

4
ответ дан 24 November 2019 в 19:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: