モジュール java.base
パッケージ java.util.stream

インタフェースGatherer<T,A,R>

型パラメータ:
T - ギャザラ操作への入力要素のタイプ
A - ギャザラ操作(多くの場合、実装の詳細として非表示)の可変状態タイプ
R - ギャザラ操作からの出力要素のタイプ

public interface Gatherer<T,A,R>
Gathererは、JavaプラットフォームのプレビューAPIです。
プレビュー機能が有効な場合のみ、プログラムでGathererを使用できます。
プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
入力要素のストリームを出力要素のストリームに変換する中間操作で、オプションでアップストリームの最後に達したときに最終アクションを適用します。 変換はステートレスまたはステートフルであり、出力を生成する前に入力をバッファリングできます。

Gatherer操作を順次実行することも、パラレル化することもできます。 -- コンビナ関数が指定されている場合。

収集操作には、次のような多くの例があります: 要素をバッチにグループ化 (ウィンドウ関数) ;連続的に類似した要素の複製解除;増分累積関数 (プレフィクス・スキャン) ;増分再順序付け関数などクラスGatherersPREVIEWは、一般的な収集操作の実装を提供します。

APIのノート:

Gathererは、オプションで中間状態を使用して入力要素を処理するために連携する4つの関数によって指定され、オプションで入力の最後に最終的なアクションを実行します。 これらは次のとおりです。

initializer()integrator()combiner()およびfinisher()の各呼出しは、意味的に同じ結果を返す必要があります。

Gathererの実装は、他のスレッド、状態インスタンスまたはダウンストリームGatherer.DownstreamPREVIEWへの参照を取得、保持または公開してはなりません。これは、渡されるメソッドの呼出し期間より長くなります。

Gathererを使用して収集操作を実行すると、次のような結果になります。

Gatherer.Downstream<? super R> downstream = ...;
A state = gatherer.initializer().get();
for (T t : data) {
    gatherer.integrator().integrate(state, t, downstream);
}
gatherer.finisher().accept(state, downstream);

ただし、ライブラリは自由に入力をパーティション分割し、パーティションに統合を実行してから、コンビナ機能を使用して部分的な結果を結合し、収集操作を実行できます。 (特定の収集操作によっては、インテグレータおよびコンビナ機能の相対コストに応じて、パフォーマンスが向上するか、低下する場合があります。)

GatherersPREVIEWの事前定義済実装に加えて、静的ファクトリ・メソッドof(...)およびofSequential(...)を使用して、ギャザラを構築できます。 たとえば、次を使用してStream.map(java.util.function.Function)と同等のものを実装するギャザラを作成できます。

public static <T, R> Gatherer<T, ?, R> map(Function<? super T, ? extends R> mapper) {
    return Gatherer.of(
        (unused, element, downstream) -> // integrator
            downstream.push(mapper.apply(element))
    );
}

Gathererはcomposedになるように設計されており、2つ以上のGathererは、andThen(Gatherer)メソッドを使用して1つのGathererに構成できます。

// using the implementation of `map` as seen above
Gatherer<Integer, ?, Integer> increment = map(i -> i + 1);

Gatherer<Object, ?, String> toString = map(i -> i.toString());

Gatherer<Integer, ?, String> incrementThenToString = increment.andThen(toString);

たとえば、順次プリフィクス・スキャンを実装するGathererは、次のように実行できます。

public static <T, R> Gatherer<T, ?, R> scan(
    Supplier<R> initial,
    BiFunction<? super R, ? super T, ? extends R> scanner) {

    class State {
        R current = initial.get();
    }

    return Gatherer.<T, State, R>ofSequential(
         State::new,
         Gatherer.Integrator.ofGreedy((state, element, downstream) -> {
             state.current = scanner.apply(state.current, element);
             return downstream.push(state.current);
         })
    );
}

使用の例:

// will contain: ["1", "12", "123", "1234", "12345", "123456", "1234567", "12345678", "123456789"]
List<String> numberStrings =
    Stream.of(1,2,3,4,5,6,7,8,9)
          .gather(
              scan(() -> "", (string, number) -> string + number)
           )
          .toList();

実装要件:
Stream.gather(Gatherer)PREVIEWなどのGathererに基づいて変換を実装するライブラリ、次の制約に従う必要があります:
  • 初期化子がdefaultInitializer()であるGatherersはステートレスとみなされ、その初期化子の起動はオプションです。
  • インテグレータがGatherer.Integrator.GreedyPREVIEWのインスタンスであるGatherersは、短絡しないことを想定でき、Gatherer.Integrator.integrate(Object, Object, Downstream)PREVIEWを呼び出す戻り値を検査する必要はありません。
  • 統合関数に渡される最初の引数(コンビナ・ファンクションに渡される引数と、フィニッシャ・ファンクションに渡される引数)は、イニシャライザまたはコンビナ・ファンクションの以前の呼出しの結果である必要があります。
  • インテグレータ、コンビナまたはフィニッシャ・ファンクションに再度渡す以外に、初期化子またはコンビナ・ファンクションの結果に対して実装は何もしないでください。
  • 状態オブジェクトがコンビナまたはフィニッシャ関数に渡されると、インテグレータ関数に再度渡されることはありません。
  • インテグレータ関数がfalseを返す場合、これ以上渡す要素がないかのように解釈されます。
  • パラレル評価の場合、収集実装では、入力が適切にパーティション化されていること、パーティションが分離で処理されていること、および両方のパーティションの統合が完了した後にのみ結合が行われることを管理する必要があります。
  • コンビナがdefaultCombiner()であるGatherersは、順次しか評価できません。 他のすべてのコンビナでは、分離して各パーティションを初期化し、falseが返されるまでインテグレータを起動し、コンビナを使用して各パーティションの状態を結合してから、結合状態でフィニッシャを起動することで、操作をパラレル化できます。 以前のパーティションの短絡を処理する場合、入力シーケンス内の後の出力および状態は破棄されます。
  • フィニッシャがdefaultFinisher()のGatherersは、ストリーム終了フックがないとみなされ、フィニッシャの起動はオプションです。
導入されたバージョン:
22
関連項目: