Итерация перечисления в 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();
}
};
}