1. ホーム
  2. java

[解決済み] Java Enumeration を Stream に変換するにはどうすればよいですか?

2023-06-23 13:48:45

質問

サードパーティのライブラリで Enumeration<String> . この列挙を、Java 8 の Stream のようなものを呼び出したい。 filter , mapflatMap を付けてください。

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

別の方法として、(1) のような、(2) のような、(3) のような、(4) のように EnumerationStream を、すべての怠惰な性質を保持しながら?

どのように解決するのか?

この回答 を作成する解決策をすでに提供しています。 Stream から Enumeration :

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

しかし、上記のコードは、「using」の犠牲になっています。 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 . 読者が新しいAPIについて学ぶことを要求しているだけです。