Ответ
В Java Stream API метод forEach() также принимает функциональный интерфейс Consumer<T>.
Ключевые отличия от forEach() в Iterable:
- Порядок выполнения: В параллельных стримах (
parallelStream()) порядок обработки элементов не гарантирован. - Потокобезопасность: Для корректной работы в параллельном режиме
Consumerдолжен быть потокобезопасным или не иметь разделяемого изменяемого состояния.
Примеры в Stream API:
List<String> names = List.of("Alice", "Bob", "Charlie");
// 1. Последовательный стрим
names.stream()
.forEach(System.out::println); // Порядок гарантирован: Alice, Bob, Charlie
// 2. Параллельный стрим
names.parallelStream()
.forEach(System.out::println); // Порядок вывода не гарантирован!
// 3. Consumer с состоянием (опасно для parallelStream!)
List<String> result = Collections.synchronizedList(new ArrayList<>());
names.parallelStream()
.forEach(result::add); // Требуется синхронизированная коллекция
Рекомендация: Для операций с побочными эффектами в стримах, где важен порядок или нужна мутация состояния, часто лучше использовать forEachOrdered() или коллектор (collect()), а не forEach().