これは基本的にのフォローアップである私のこの答え。
私はカスタムコレクターに取り組んでいることを想定していたとしaccumulator
、常に供給者によって返されたコレクションにいくつかの要素が追加されます、ときという万が一があるcombiner
と呼ばれ、中間結果の一つが空になりますか?例は、おそらく理解することがずっと簡単です。
私が持っていると仮定しList
た場合、数字のを、私はリストのリストでそれを分割したい2
セパレータがあります。例えば、私が持っているので1, 2, 3, 4, 2, 8
、結果がでなければなりません[[1], [3, 4], [8]]
。これは実際に達成するために複雑ではありません(あまりにも多くのコードを判断してはいけない、私はこの質問を書くことができちょうどので、高速で何かを書きました)。
List<List<Integer>> result = Stream.of(1, 2, 3, 4, 2, 8)
.collect(Collector.of(
() -> new ArrayList<>(),
(list, elem) -> {
if (list.isEmpty()) {
List<Integer> inner = new ArrayList<>();
inner.add(elem);
list.add(inner);
} else {
if (elem == 2) {
list.add(new ArrayList<>());
} else {
List<Integer> last = list.get(list.size() - 1);
last.add(elem);
}
}
},
(left, right) -> {
// This is the real question here:
// can left or right be empty here?
return left;
}));
これは、この例では、おそらく無関係ですが、質問です:1つの要素ができるcombiner
空になりますかList
?私は本当に言うことを傾けていますNO
マニュアルにこれらのは次のように呼ばれているので、:
コンバイナ-受け付け会合、非干渉、ステートレス機能二つの部分結果容器とマージして。
まあことは、部分的に私には表示されaccumulator
、彼らが到達する前に、それらに呼ばれていたcombiner
が、念になりたかったです。
アキュムレータはマージする前にコンテナに適用されているという保証はありません。言い換えれば、マージのリストが空でもよいです。
このことを証明するために:
IntStream.range(0, 10).parallel().boxed()
.filter(i -> i >= 3 && i < 7)
.collect(ArrayList::new, List::add, (l1,l2)->{
System.out.println(l1.size()+" + "+l2.size());
l1.addAll(l2);
});
私のマシンでは、それが印刷されます。
0 + 0
0 + 0
0 + 0
1 + 1
0 + 2
0 + 2
1 + 1
2 + 0
2 + 2
フィルタ演算の結果がまだ知られていない場合に作業負荷分割は、ソースリストで起こります。各チャンクは、任意の要素がアキュムレータに到着したかどうかを再チェックすることなく、同じように処理されます。
Javaの9から始まる、あなたはまた、のような何かを行うことができますことを心
IntStream.range(0, 10).parallel().boxed()
.collect(Collectors.filtering(i -> i >= 3 && i < 7, Collectors.toList()));
これは(ここで、コレクタもう一つの理由であるtoList()
フィルタリングが外起こるようコレクタ)は、空のコンテナに遭遇するように準備する必要がありStream
、実装およびaccept
化合物コレクターのアキュムレータのコールが常に意味するものではないaccept
下流コレクタのアキュムレータにコールを。
空容器を取り扱うことができるという要件がで指定されているCollector
ドキュメント:
シーケンシャル及びパラレル実行は同等の結果をもたらすことを確実にするために、集電機能が満足しなければならないアイデンティティと連想制約。
アイデンティティの制約は、任意の部分的に蓄積された結果のために、空の結果コンテナとそれを組み合わせること同等の結果を生成しなければならないと述べています。すなわち、部分的に蓄積された結果を
a
アキュムレータ及びコンバイナ呼び出しのいずれかのシリーズの結果である、a
と同等でなければなりませんcombiner.apply(a, supplier.get())
。