Пользовательский сборщик - вот ответ:
Entry<List<Integer>, Integer> result = list.stream()
.collect(Collector.of(
() -> new SimpleEntry<>(new ArrayList<>(), 0),
(l, x) -> {
if (l.getKey().size() < 10) {
l.getKey().add(x);
}
l.setValue(l.getValue() + 1);
},
(left, right) -> {
List<Integer> leftList = left.getKey();
List<Integer> rightList = right.getKey();
while (leftList.size() < 10 && rightList.size() > 0) {
leftList.add(rightList.remove(0));
}
left.setValue(left.getValue() + right.getValue());
return left;
}));
Предположим, у вас есть этот код:
Set.of(1, 2, 3, 4)
.stream()
.parallel()
.collect(Collector.of(
ArrayList::new,
(list, ele) -> {
System.out.println("Called accumulator");
list.add(ele);
},
(left, right) -> {
System.out.println("Combiner called");
left.addAll(right);
return left;
},
new Characteristics[] { Characteristics.CONCURRENT }));
Прежде чем мы начнем думать об этом коде (важно, насколько он правильныйдля примера) нам нужно немного прочитать документацию для характеристики CONCURRENT
:
Если коллектор CONCURRENT также не является UNORDERED, то он должен оцениваться одновременно только в случае его применения кнеупорядоченный источник данных.
Эта документация в основном говорит о том, что если ваш сборщик CONCURRENT
и , то источником потока является UNORDERED
(например, Set
) или мы явно вызываем unordered
, тогда слияние никогда не будет вызвано.
Если вы запустите предыдущий код, вы увидите, что Combiner called
никогда не присутствует в выходных данных.
Еслиизменив Set.of(1, 2, 3, 4)
на List.of(1, 2, 3, 4)
, вы увидите другую картинку (игнорируйте правильность полученного результата - поскольку ArrayList
не является поточно-ориентированным, но это не главное).Если у вас есть источник потока, равный List
и в то же время вы звоните unordered
, вы снова увидите, что вызывается только аккумулятор, то есть:
List.of(1, 2, 3, 4)
.stream()
.unordered()
.parallel()
.collect(Collector.of(
ArrayList::new,
(list, ele) -> {
System.out.println("Called accumulator");
list.add(ele);
},
(left, right) -> {
System.out.println("Combiner called");
left.addAll(right);
return left;
},
new Characteristics[] { Characteristics.CONCURRENT }));