Нормальное сокращение предназначено для объединения двух неизменяемых значений, таких как int, double и т. Д., И создания нового; это неизменное сокращение. Напротив, метод collect предназначен для изменения контейнера для накопления результата, который он должен произвести.
Чтобы проиллюстрировать проблему, предположим, что вы хотите добиться Collectors.toList()
простого сокращения, например
List<Integer> numbers = stream.reduce(
new ArrayList<Integer>(),
(List<Integer> l, Integer e) -> {
l.add(e);
return l;
},
(List<Integer> l1, List<Integer> l2) -> {
l1.addAll(l2);
return l1;
});
Это эквивалент Collectors.toList()
. Однако в этом случае вы изменяете файл List<Integer>
. Как мы знаем, ArrayList
он не является потокобезопасным и небезопасно добавлять / удалять из него значения во время итерации, поэтому вы получите либо одновременное исключение, ArrayIndexOutOfBoundsException
либо какое-либо исключение (особенно при параллельном запуске) при обновлении списка или объединителя. пытается объединить списки, потому что вы изменяете список, накапливая (добавляя) к нему целые числа. Если вы хотите сделать этот потокобезопасным, вам нужно каждый раз передавать новый список, что снизит производительность.
Напротив, Collectors.toList()
работает аналогичным образом. Однако он гарантирует безопасность потоков, когда вы накапливаете значения в списке. Из документации к collect
методу :
Выполняет изменяемую операцию сокращения для элементов этого потока с помощью Collector. Если поток параллельный, а коллектор является параллельным, и либо поток неупорядочен, либо коллектор неупорядочен, то одновременное сокращение будет выполнено. При параллельном выполнении несколько промежуточных результатов могут быть созданы, заполнены и объединены, чтобы поддерживать изоляцию изменяемых структур данных. Следовательно, даже при параллельном выполнении со структурами данных, не защищенными от потоков (такими как ArrayList), для параллельного сокращения не требуется дополнительной синхронизации.
Итак, чтобы ответить на ваш вопрос:
Когда бы вы использовали collect()
vs reduce()
?
если у вас есть незыблемые ценности , такие как ints
, doubles
, Strings
то нормальное снижение работает просто отлично. Однако, если вам нужно reduce
преобразовать свои значения в, скажем, List
(изменяемую структуру данных), вам необходимо использовать изменяемое сокращение с помощью этого collect
метода.