web-dev-qa-db-ja.com

Java 8で列挙を繰り返す

Lambda Expressionを使用してEnumerationを反復処理することはできますか?次のコードスニペットのLambda表現はどうなりますか?

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

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

}

ストリームが見つかりませんでした。

70
Tapas Bose

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_機能に注意してください)…

33
Holger

(この答えは、多くのオプションの1つを示しています。 持っている 受け入れマークがあった、それが最高のものであることを意味するものではありません。他の答えを読んで、あなたがいる状況に応じて答えを選ぶことをお勧めします。IMO:
-for Java 8 Holger's answer が最も優れています。シンプルであるだけでなく、鉱山ソリューションで発生する追加の反復を必要としないためです。
-for Java 9私は Tagir Valeev answer )から解決策を選択します


Enumeration の要素を ArrayListCollections.list でコピーして使用できます好む

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

コードに多くのEnumerationsがある場合、EnumerationStreamに変換する静的ヘルパーメソッドを作成することをお勧めします。静的メソッドは次のようになります。

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);
}

static importでメソッドを使用します。 Holgerのソリューションとは対照的に、さまざまなstream操作の恩恵を受けることができます。これにより、既存のコードがさらに簡単になります。以下に例を示します。

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

Java-9以降、新しいデフォルトメソッド Enumeration.asIterator() が追加され、純粋なJavaソリューションがより簡単になります。

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

次の標準機能の組み合わせを使用できます。

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

NONNULLDISTINCTなどの特性を追加することもできます。

静的インポートを適用すると、これはさらに読みやすくなります。

_stream(spliteratorUnknownSize(toIterator(enumeration), IMMUTABLE), false)
_

これで、標準のJava 8ストリームを任意の方法で使用できます!並列処理にtrueを渡すことができます。

列挙型からイテレータに変換するには、次のいずれかを使用します。

  • CollectionUtils.toIterator() Spring 3.2から、または使用できます
  • IteratorUtils.asIterator() Apache Commons Collections 3.2から
  • Iterators.forEnumeration() Google Guavaから
11
Arne Burmeister

Java 8の場合、列挙からストリームへの最も単純な変換は次のとおりです。

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

6
Marek Gregor

これは古い質問であることは知っていますが、Collections.asListおよびStream機能の代替を提示したかったのです。質問のタイトルは「列挙の反復」であるため、ラムダ式を使用したい場合があることを認識していますが、列挙オブジェクトが例外をスローし、forループがより大きなtry-コードセグメントをキャッチします(ラムダでは、宣言された例外をラムダ内でキャッチする必要があります)。そのために、ここではラムダを使用してforループで使用可能で列挙をプリロードしないIterableを作成しています。

 /**
 * 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();
        }
    };
}
4
user579013