T
- リダクション操作の入力要素の型A
- リダクション操作の可変蓄積の型(通常は実装詳細として隠蔽される)R
- リダクション操作の結果の型public interface Collector<T,A,R>
可変リダクション操作の例としては、Collection
への要素の蓄積、StringBuilder
を使用した文字列の連結、要素に関するサマリー情報(合計、最小、最大、平均など)の計算、ピボット・テーブル・サマリー(「販売業者別の最大金額取引」など)の計算、などが挙げられます。クラスCollectors
には、一般的な可変リダクションの実装が多数用意されています。
Collector
の仕様を決定する4つの関数は、互いに連携して動作することにより、可変結果コンテナにエントリを蓄積し、オプションでその結果に対して最終的な変換を実行します。これらは次のとおりです。
supplier()
)accumulator()
)combiner()
)finisher()
)また、コレクタにはCollector.Characteristics.CONCURRENT
などの一連の特性も含まれています。リダクション実装は、これらの特性によって提供されるヒントをパフォーマンス向上のために使用できます。
コレクタを使用したリダクションの順次実装は、サプライヤ関数を使って単一の結果コンテナを作成し、入力要素ごとに1回ずつアキュムレータ関数を呼び出します。並列実装は、入力を分割し、パーティションごとに結果コンテナを作成し、各パーティションの内容をそのパーティション用のサブ結果内に蓄積した後、コンバイナ関数を使ってサブ結果をマージして1つの結果にまとめます。
順次実行と並列実行で同一の結果が得られるようにするには、コレクタの関数が同一性制約と結合性制約を満たす必要があります。
同一性制約とは、部分的に蓄積された任意の結果について、その結果を空の結果コンテナと結合したときに元と同じ結果が生成される必要がある、というものです。つまり、一連のアキュムレータ呼出しやコンバイナ呼出しの結果として得られた、部分的に蓄積された結果a
について、a
はcombiner.apply(a, supplier.get())
と等しくなる必要があります。
結合性制約とは、計算を分割しても同一の結果が得られなければいけない、というものです。つまり、任意の入力要素t1
とt2
について、以下の計算の結果r1
とr2
が等しくなる必要があります。
A a1 = supplier.get();
accumulator.accept(a1, t1);
accumulator.accept(a1, t2);
R r1 = finisher.apply(a1); // result without splitting
A a2 = supplier.get();
accumulator.accept(a2, t1);
A a3 = supplier.get();
accumulator.accept(a3, t2);
R r2 = finisher.apply(combiner.apply(a2, a3)); // result with splitting
UNORDERED
特性を持たないコレクタでは、蓄積された2つの結果a1
とa2
が等しくなるのは、finisher.apply(a1).equals(finisher.apply(a2))
の場合になります。順序付けされていないコレクタでは、等価性の条件が緩和され、順序の違いに関する非等価が許容されるようになります。(たとえば、要素をList
に蓄積した順序付けされていないコレクタは、2つのリストが同じ要素を含んでいれば両者を等しいとみなし、順序は無視します。)
Stream.collect(Collector)
のような、Collector
に基づいてリダクションを実装しているライブラリは、次の制約に従う必要があります。
Collector
に追加の同期を実装しなくても収集を並列に行える。リダクション実装は、入力が正しく分割され、各パーティションが隔離状態で処理され、蓄積完了後にのみ結合が実行されるように管理する必要がある。Collector.Characteristics.UNORDERED
特性を持つ場合、または元となるデータが順序付けされていない場合だけにすべきである。Collectors
の定義済の実装のほかに、staticファクトリメソッドof(Supplier, BiConsumer, BinaryOperator, Characteristics...)
を使っても、コレクタを構築できます。たとえば、ウィジェットをTreeSet
内に蓄積するコレクタは、次のようにして作成できます。
Collector<Widget, ?, TreeSet<Widget>> intoSet =
Collector.of(TreeSet::new, TreeSet::add,
(left, right) -> { left.addAll(right); return left; });
(この動作は、定義済のコレクタCollectors.toCollection(Supplier)
でも実装されています)。Collector
によるリダクション操作の実行時には、次と同等の結果が生成されるべきです。
R container = collector.supplier().get();
for (T t : data)
collector.accumulator().accept(container, t);
return collector.finisher().apply(container);
ただしライブラリは、入力を自由に分割し、パーティションごとにリダクションを実行した後、コンバイナ関数を使って部分的な結果を結合することにより、並列リダクションを実現することができます。(そのパフォーマンスの善し悪しは、実際のリダクション操作ごとに異なる可能性があります。具体的には、アキュムレータ関数やコンバイナ関数の相対的なコストによって決まります。)
コレクタは合成可能なように設計されています。Collectors
のメソッドの多くは、あるコレクタを受け取って新しいコレクタを生成する関数になっています。たとえば、従業員ストリームの給料の合計を計算する次のようなコレクタがあるとします。
Collector<Employee, ?, Integer> summingSalaries
= Collectors.summingInt(Employee::getSalary))
給料の部門別合計の表を作成するコレクタを作成する場合、Collectors.groupingBy(Function, Collector)
を使えば「給料の合計」のロジックを再利用できます。
Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
= Collectors.groupingBy(Employee::getDepartment, summingSalaries);
Stream.collect(Collector)
, Collectors
修飾子と型 | インタフェースと説明 |
---|---|
static class |
Collector.Characteristics
リダクション実装の最適化に使用可能な、
Collector のプロパティーを示す特性。 |
修飾子と型 | メソッドと説明 |
---|---|
BiConsumer<A,T> |
accumulator()
可変結果コンテナに値を折りたたむ関数。
|
Set<Collector.Characteristics> |
characteristics()
このCollectorの特性を示す
Collector.Characteristics のSet を返します。 |
BinaryOperator<A> |
combiner()
2つの部分的な結果を受け取ってマージする関数。
|
Function<A,R> |
finisher()
中間蓄積の型
A から最終結果の型R への最終的な変換を実行します。 |
static <T,A,R> Collector<T,A,R> |
of(Supplier<A> supplier, BiConsumer<A,T> accumulator, BinaryOperator<A> combiner, Function<A,R> finisher, Collector.Characteristics... characteristics)
指定された
supplier 、accumulator 、combiner 、およびfinisher 関数で記述される新しいCollector を返します。 |
static <T,R> Collector<T,R,R> |
of(Supplier<R> supplier, BiConsumer<R,T> accumulator, BinaryOperator<R> combiner, Collector.Characteristics... characteristics)
指定された
supplier 、accumulator 、およびcombiner 関数で記述される新しいCollector を返します。 |
Supplier<A> |
supplier()
新しい可変結果コンテナを作成して返す関数。
|
BiConsumer<A,T> accumulator()
BinaryOperator<A> combiner()
Function<A,R> finisher()
A
から最終結果の型R
への最終的な変換を実行します。
特性IDENTITY_TRANSFORM
が設定されている場合、この関数は、A
からR
への非チェック・キャストによる恒等変換とみなせます。
Set<Collector.Characteristics> characteristics()
Collector.Characteristics
のSet
を返します。このセットは不変であるべきです。static <T,R> Collector<T,R,R> of(Supplier<R> supplier, BiConsumer<R,T> accumulator, BinaryOperator<R> combiner, Collector.Characteristics... characteristics)
supplier
、accumulator
、およびcombiner
関数で記述される新しいCollector
を返します。結果のCollector
は、Collector.Characteristics.IDENTITY_FINISH
特性を持ちます。T
- 新しいコレクタの入力要素の型R
- 新しいコレクタの中間蓄積結果と最終結果の型supplier
- 新しいコレクタのサプライヤ関数accumulator
- 新しいコレクタのアキュムレータ関数combiner
- 新しいコレクタのコンバイナ関数characteristics
- 新しいコレクタのコレクタ特性Collector
NullPointerException
- いずれかの引数がnullの場合static <T,A,R> Collector<T,A,R> of(Supplier<A> supplier, BiConsumer<A,T> accumulator, BinaryOperator<A> combiner, Function<A,R> finisher, Collector.Characteristics... characteristics)
supplier
、accumulator
、combiner
、およびfinisher
関数で記述される新しいCollector
を返します。T
- 新しいコレクタの入力要素の型A
- 新しいコレクタの中間蓄積の型R
- 新しいコレクタの最終結果の型supplier
- 新しいコレクタのサプライヤ関数accumulator
- 新しいコレクタのアキュムレータ関数combiner
- 新しいコレクタのコンバイナ関数finisher
- 新しいコレクタのフィニッシャ関数characteristics
- 新しいコレクタのコレクタ特性Collector
NullPointerException
- いずれかの引数がnullの場合 バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright© 1993, 2014, Oracle and/or its affiliates. All rights reserved.