Подтвердить что ты не робот

Java 8 способ работы с перечислением

Мне интересно, как лучше всего на Java 8 работать со всеми значениями перечисления. В частности, когда вам нужно получить все значения и добавить их где-нибудь, например, предположив, что у нас есть следующее перечисление:

public enum Letter {
 A, B, C, D;
}

Я мог бы, конечно, сделать следующее:

for (Letter l : Letter.values()) {
    foo(l);
}

Но я мог бы также добавить следующий метод в определение перечисления:

public static Stream<Letter> stream() {
    return Arrays.stream(Letter.values());
}

И затем замените for for сверху:

Letter.stream().forEach(l -> foo(l));

Является ли этот подход ОК или имеет некоторые недостатки в дизайне или производительности? Кроме того, почему у перечислений нет метода stream()?

4b9b3361

Ответ 1

Три вопроса: ответ из трех частей:

Все в порядке с дизайнерской точки зрения?

Совершенно верно. Ничего плохого в этом нет. Если вам нужно сделать много итераций по вашему перечислению, поток API - это чистый способ пойти и скрыть плиту котла за небольшим методом. Хотя Id больше рассматривает OldCumudgeon версию.

В порядке ли с точки зрения производительности?

Скорее всего, это не имеет значения. В большинстве случаев перечисления не так уж велики. Поэтому любые накладные расходы для одного метода или другого, вероятно, не имеют значения в 99,9% случаев.

Конечно, есть 0,1%, где он. В этом случае: правильно измеряйте, используя данные реального мира и потребителей.

Если бы мне пришлось делать ставки, Id ожидает, что цикл for each будет более быстрым, поскольку он больше привязывается к модели памяти, но не догадывается, когда речь идет о производительности, и не настраивается, прежде чем возникает настоятельная потребность в настройке. Напишите свой код таким образом, который является правильным во-первых, легко читается вторым и только потом беспокоится о производительности стиля кода.

Почему arent Enums правильно интегрированы в Stream API?

Если вы сравните API Javas Stream с эквивалентом на многих других языках, он выглядит серьезно ограниченным. Существуют различные фрагменты, которые отсутствуют (например, потоки и опции для повторного использования как потоки). С другой стороны, внедрение Stream API было, безусловно, огромным изменением для API. Он был отложен несколько раз по причине. Поэтому я предполагаю, что Oracle хочет ограничить изменения в наиболее важных случаях использования. В любом случае, Enums arent так сильно использовал. Конечно, у каждого проекта есть пара из них, но они ничто по сравнению с количеством списков и других коллекций. Даже когда у вас есть Enum, во многих случаях вы никогда не будете перебирать его. С другой стороны, списки и наборы, вероятно, повторяются почти каждый раз. Я предполагаю, что это были причины, по которым Enums не получили свой собственный адаптер в мире Stream. Хорошо, посмотрим, добавится ли больше в будущие версии. И до этого вы всегда можете использовать Arrays.stream.

Ответ 2

Я бы пошел на EnumSet. Поскольку forEach() также определен в Iterable, вы можете вообще не создавать поток:

EnumSet.allOf(Letter.class).forEach(x -> foo(x));

Или с помощью ссылки на метод:

EnumSet.allOf(Letter.class).forEach(this::foo);

Тем не менее, oldschool for-loop чувствует себя немного проще:

for (Letter x : Letter.values()) {
    foo(x);
}

Ответ 3

Мое предположение заключается в том, что перечисления ограничены по размеру (то есть размер не ограничен языком, но ограниченным использованием), и поэтому им не нужен собственный поток api. Потоки очень хороши, когда вам приходится манипулировать преобразованием и вспоминать элементы в потоке; это не обычный случай использования для Enum (обычно вы перебираете значения enum, но редко вам нужно преобразовывать, отображать и собирать их).

Если вам нужно только выполнить действие над каждым элементом, возможно, вы должны выставить только метод forEach

     public static void forEach(Consumer<Letter> action) {
            Arrays.stream(Letter.values()).forEach(action);
     }

     .... //example of usage
     Letter.forEach(e->System.out.println(e));

Ответ 4

Я думаю, что самый короткий код для получения констант перечисления Stream равен Stream.of(Letter.values()). Это не так хорошо, как Letter.values().stream(), но это проблема с массивами, а не специально перечисляет.

Кроме того, почему в перечислениях нет метода stream()?

Вы правы, что самым приятным звонком будет Letter.stream(). К сожалению, класс не может иметь два метода с одной и той же сигнатурой, поэтому невозможно было бы неявно добавлять статический метод stream() к каждому перечислению (так же, как каждый перечислитель имеет неявно добавленный статический метод values()), поскольку это будет разбивать все существующие перечисления, которые уже имеют статический или экземплярный метод без параметров, называемых stream().

Является ли этот подход ОК?

Я так думаю. Недостатком является то, что Stream является статическим методом, поэтому нет возможности избежать дублирования кода; он должен быть добавлен к каждому перечислению отдельно.