2015-10-20 3 views
15

私にEnumeration<String>というサードパーティのライブラリがあります。私はその列挙型をJava 8 Streamとして遅れて処理し、filtermapflatMapなどを呼び出しています。Java EnumerationをStreamに変換するにはどうすればよいですか?

これを持つ既存のライブラリはありますか?私は既にGuavaとApache Commonsを参照していますので、いずれかの方が理想的な解決策を持っているとします。

さらに、EnumerationStreamにする最も簡単で簡単な方法は何ですか?

+1

関連[Java 8の列挙を反復](http://stackoverflow.com/q/23261803/217324) –

+0

関連する質問は、列挙型(Java 1.0)を「反復子」にする方法を尋ねています。 (Java 1.2)。私はそれを 'Stream'(Java 1.8)にする方法を尋ねています。リンクされた質問の最後の答えがこれに答えているように見えますが、その答えは質問された質問に対しては間違っています。その答えは、将来の検索者がうまく見つけることができるようにここに提供する必要があります。おそらく@ArneBurmeisterはこの質問を直接回答するように答えをここにコピーしたいと思いますか? –

+2

リンクされた質問の回答として再開されても、怠け者の行動については議論されません。また、リンクされた質問の範囲ではないので、 'Stream'を作成する別の方法を投稿するのは適切な場所ではありません。 – Holger

答えて

19

This answerすでに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); 
} 

それは勝った結果として得られたStreamは、Streamほど怠惰であることを強調しなければなりませんターミナルアクションが開始される前にすべてのアイテムを処理し、ターミナル操作が短絡している場合、必要なだけ多くのアイテムを繰り返します。

まだ改善の余地があります。すべての要素を直接処理する方法がある場合は、常にforEachRemainingメソッドを追加します。前記方法は、最も非短絡操作について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(); 
       } 
       public void forEachRemaining(Consumer<? super T> action) { 
        while(e.hasMoreElements()) action.accept(e.nextElement()); 
       } 
      }, 
      Spliterator.ORDERED), false); 
} 

しかし、上記のコードは、「それはとても馴染みだからIteratorを使用して」パターンの犠牲者です。作成したIteratorは新しいSpliteratorインタフェースの実装に包まれ、直接Spliteratorを実装する上で何の利点を提供しないれます:ソースコードレベルで

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) { 
    return StreamSupport.stream(
     new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) { 
      public boolean tryAdvance(Consumer<? super T> action) { 
       if(e.hasMoreElements()) { 
        action.accept(e.nextElement()); 
        return true; 
       } 
       return false; 
      } 
      public void forEachRemaining(Consumer<? super T> action) { 
       while(e.hasMoreElements()) action.accept(e.nextElement()); 
      } 
    }, false); 
} 

は、この実装は Iteratorベースのと同じくらい簡単ですが、排除します Spliteratorから Iteratorへの委任。それが唯一の

4

Guava docsによると、あなたはIterators.forEnumeration()メソッドを使用することができます...新しいAPIについて学ぶために読者を必要とします。

Enumeration<Something> enumeration = ...; 

Iterator<SomeThing> iterator = Iterators.forEnumeration(enumeration); 

そしてthis questionで、イテレータからのストリームを取得する方法を説明します

のJava 9で
Stream<Something> stream = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(
     iterator, Spliterator.ORDERED), 
    false); 
+0

この場合、iterableは実際にはIterableではありませんが、正確に1回繰り返すことができます。 – dfogni

+0

@dfogniストリームでも同じことが起こります。彼らはこう言っています: –

+2

しかし、あなたは 'Iterator'から' Spliterator'を作成して 'StreamSupport.stream'に渡すことだけに興味があるので、疑わしい' Iterable'の作成を避けることができます。そのためには、['spliteratorUnknownSize(...)'](http://docs.oracle.com/javase/8/docs/api/java/util/Spliterators.html#spliteratorUnknownSize-java.util.Iterator-int- )。それはとにかく使用される方法です、ラムダで実装された 'Iterable'はそれを隠すだけです。 – Holger

11

(まだこれを書いている時点ではリリースされていない)、ワンライナーでStreamEnumerationを変換することが可能となります。

Enumeration<String> en = ... ; 
Stream<String> str = StreamSupport.stream(Spliterators.spliteratorUnknownSize(en.asIterator(), Spliterator.ORDERED), false); 

(まあ、それはかなり長い行です。)

は、Java 9でない場合は、手動でHolger's answerで与えられた技術を使用してIteratorEnumerationを変換することができます。私StreamExライブラリで

+9

行を長くすると、ほぼすべてを1ライナーにすることができます^^ – Holger

3

仕事をして、簡単な方法StreamEx.of(Enumeration)があります:

Stream<String> stream = StreamEx.of(enumeration); 

なお、それだけではなく@Holgerソリューションへのショートカットが、別の方法で実現。特に、Spliterators.spliteratorUnknownSize()を含むソリューションと比較して、大幅に優れた並列実行特性を備えています。

28

バニラJavaを使用していない理由:Collections.listは最初の要素をコピーする列挙を反復しますよう

Collections.list(enumeration).stream()... 

しかし@MicahZoltuによってmentionnedとして、列挙内の項目数は、考慮しなければなりませんArrayListにあります。そこから通常のstreamメソッドを使用できます。これは多くのコレクションストリーム操作では一般的ですが、エニュメレーションが大きすぎると(無限のように)、リスト内で列挙を変換しなければならないため、ここで説明する他の方法を代わりに使用する必要があるため、

+2

これは 'enumeration'全体を列挙してリストにし、リストへのストリームアクセスを提供します。列挙型が小さければ、これはおそらく合理的なアプローチです。エニュメレーションが非常に大きい場合、これは高価で不必要な操作になる可能性があります。列挙が無限であれば、アプリケーションがクラッシュします。 –

+0

@MicahZoltu確かに。それが考慮すべきポイントですが、私は答えを更新します。ありがとう – Brice

関連する問題