Итерация перечисления в Java 8

Можно ли повторять итерацию Enumeration с помощью выражения Lambda? Каким будет представление Лямбды следующего фрагмента кода:

Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();

while (nets.hasMoreElements()) {
    NetworkInterface networkInterface = nets.nextElement();

}

Я не нашел в нем потока.

Ответ 1

Если вам не нравится тот факт, что Collections.list(Enumeration) копирует все содержимое во временный список до начала итерации, вы можете помочь себе простым способом:

public static <T> void forEachRemaining(Enumeration<T> e, Consumer<? super T> c) {
  while(e.hasMoreElements()) c.accept(e.nextElement());
}

Тогда вы можете просто сделать forEachRemaining(enumeration, lambda-expression); (вспомнить функцию import static)...

Ответ 2

(Этот ответ показывает один из многих вариантов. Тот факт, что у него есть отметка о приемке, не означает, что он является лучшим. Я предлагаю прочитать другие ответы и выбрать их в зависимости от ситуации, в которой вы находитесь. IMO:
- для Java 8 Хольгер ответит лучше, потому что, помимо простоты, он не требует дополнительной итерации, что происходит в моем решении.
- для Java 9 я бы выбрал решение от ответа Тагира Валеева)


Вы можете скопировать элементы из вашего Enumeration в ArrayList с Collections.list а затем использовать его как

Collections.list(yourEnumeration).forEach(yourAction);

Ответ 3

Если в вашем коде много перечислений, я рекомендую создать статический вспомогательный метод, который преобразует Enumeration в Stream. Статический метод может выглядеть следующим образом:

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
            new Iterator<T>() {
                public T next() {
                    return e.nextElement();
                }
                public boolean hasNext() {
                    return e.hasMoreElements();
                }
            },
            Spliterator.ORDERED), false);
}

Использовать метод со статическим импортом. В отличие от решения Holger, вы можете воспользоваться различными потоковыми операциями, которые могут сделать существующий код еще более простым. Вот пример:

Map<...> map = enumerationAsStream(enumeration)
    .filter(Objects::nonNull)
    .collect(groupingBy(...));

Ответ 4

Так как Java-9 будет новый метод по умолчанию Enumeration.asIterator(), который упростит чистое решение Java:

nets.asIterator().forEachRemaining(iface -> { ... });

Ответ 5

Вы можете использовать следующую комбинацию стандартных функций:

StreamSupport.stream(Spliterators.spliteratorUnknownSize(CollectionUtils.toIterator(enumeration), Spliterator.IMMUTABLE), parallel)

Вы также можете добавить дополнительные характеристики, такие как NONNULL или DISTINCT.

После применения статического импорта это станет более читаемым:

stream(spliteratorUnknownSize(toIterator(enumeration), IMMUTABLE), false)

теперь у вас есть стандартный поток Java 8, который можно использовать каким-либо образом! Вы можете передать true для параллельной обработки.

Для преобразования из Enumeration в Iterator используйте любой из:

  • CollectionUtils.toIterator() от Spring 3.2 или вы можете использовать
  • IteratorUtils.asIterator() из коллекции Apache Commons 3.2
  • Iterators.forEnumeration() от Google Guava

Ответ 6

Для Java 8 самое простое преобразование перечисления в поток:

Collections.list(NetworkInterface.getNetworkInterfaces()).stream()

Ответ 7

Я знаю, что это старый вопрос, но я хотел представить альтернативу функциональности Collections.asList и Stream. Поскольку вопрос озаглавлен "Итерация перечисления", я признаю, что иногда вы хотите использовать лямбда-выражение, но расширенный цикл может быть предпочтительнее, поскольку перечисляемый объект может вызвать исключение, а цикл for легче инкапсулировать в большей попытке. сегмент кода catch (лямбды требуют, чтобы объявленные исключения были перехвачены в лямбде). Для этого здесь используется лямбда-выражение для создания Iterable, который можно использовать в цикле for и не загружать предварительно перечисление:

 /**
 * Creates lazy Iterable for Enumeration
 *
 * @param <T> Class being iterated
 * @param e Enumeration as base for Iterator
 * @return Iterable wrapping Enumeration
 */
public static <T> Iterable<T> enumerationIterable(Enumeration<T> e)
{
    return () -> new Iterator<T>()
    {
        @Override
        public T next()
        {
            return e.nextElement();
        }

        @Override
        public boolean hasNext()
        {
            return e.hasMoreElements();
        }
    };
}