1. 概要

列挙は、Javaの最初のバージョン(JDK 1.0)のインターフェースです。 このインターフェースは汎用であり、は一連の要素への遅延アクセスを提供します。 新しいバージョンのJavaにはより優れた代替手段がありますが、レガシー実装は列挙インターフェースを使用して結果を返す場合があります。  したがって、レガシー実装を最新化するために、開発者はEnumerationオブジェクトをJavaStreamAPIに変換する必要がある場合があります。

この短いチュートリアルでは、列挙オブジェクトをJavaストリームAPIに変換するためのユーティリティメソッドを実装します。 その結果、filtermapなどのストリームメソッドを使用できるようになります。

2. Javaの列挙インターフェイス

列挙オブジェクトの使用法を説明する例から始めましょう。

public static <T> void print(Enumeration<T> enumeration) {
    while (enumeration.hasMoreElements()) {
        System.out.println(enumeration.nextElement());
    }
}

列挙には、hasMoreElementsnextElementの2つの主要なメソッドがあります。 要素のコレクションを反復処理するには、両方のメソッドを一緒に使用する必要があります。

3. Spliteratorの作成

最初のステップとして、AbstractSpliterator抽象クラスの具象クラスを作成します。 このクラスは、列挙オブジェクトをSpliteratorインターフェースに適合させるために必要です。

public class EnumerationSpliterator<T> extends AbstractSpliterator<T> {

    private final Enumeration<T> enumeration;

    public EnumerationSpliterator(long est, int additionalCharacteristics, Enumeration<T> enumeration) {
        super(est, additionalCharacteristics);
        this.enumeration = enumeration;
    }
}

クラスの作成に加えて、コンストラクターも作成する必要があります。 最初の2つのパラメーターをsuperコンストラクターに渡す必要があります。 最初のパラメーターは、Spliteratorの推定サイズです。 2つ目は、追加の特性を定義するためのものです。 最後に、最後のパラメーターを使用して、列挙オブジェクトを受け取ります。

また、tryAdvanceメソッドとforEachRemainingメソッドをオーバーライドする必要があります。 これらは、 Stream APIによって、列挙の要素に対してアクションを実行するために使用されます。

@Override
public boolean tryAdvance(Consumer<? super T> action) {
    if (enumeration.hasMoreElements()) {
        action.accept(enumeration.nextElement());
        return true;
    }
    return false;
}

@Override
public void forEachRemaining(Consumer<? super T> action) {
    while (enumeration.hasMoreElements())
        action.accept(enumeration.nextElement());
}

4. 列挙ストリームに変換しています

これで、 EnumerationSpliterator クラスを使用して、 StreamSupportAPIを使用して変換を実行できるようになりました。

public static <T> Stream<T> convert(Enumeration<T> enumeration) {
    EnumerationSpliterator<T> spliterator 
      = new EnumerationSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED, enumeration);
    Stream<T> stream = StreamSupport.stream(spliterator, false);

    return stream;
}

この実装では、EnumerationSpliteratorクラスのインスタンスを作成する必要があります。 Long.MAX_VALUE は、推定サイズのデフォルト値です。 Spliterator.ORDERED は、ストリームが列挙によって提供される順序で要素を反復することを定義します。

次に、StreamSupportクラスからstreamメソッドを呼び出す必要があります。 EnumerationSpliteratorインスタンスを最初のパラメーターとして渡す必要があります。 最後のパラメーターは、ストリームが並列か順次かを定義することです。

5. 実装のテスト

convert メソッドをテストすることで、列挙に基づいて有効なStreamオブジェクトを作成できるようになったことを確認できます。

@Test
public void givenEnumeration_whenConvertedToStream_thenNotNull() {
    Vector<Integer> input = new Vector<>(Arrays.asList(1, 2, 3, 4, 5));

    Stream<Integer> resultingStream = convert(input.elements());

    Assert.assertNotNull(resultingStream);
}

6. 結論

このチュートリアルでは、列挙Streamオブジェクトに変換する方法を示しました。 ソースコードは、いつものように、GitHubにあります。