Ответ
forEach в Java Stream API является конечным (terminal) методом. Он завершает поток, выполняя действие для каждого элемента, и не возвращает новый Stream.
Пример:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
.filter(name -> name.startsWith("A"))
.forEach(System.out::println); // Конечная операция
Ключевые особенности:
- После
forEachнельзя вызвать другие методы потока — это вызовет ошибку компиляции. - В параллельных стримах (
parallelStream()) порядок выполнения не гарантируется. Для сохранения порядка используйтеforEachOrdered. - Сам метод не изменяет исходную коллекцию, но действие внутри (например, вызов сеттера) может изменить состояние элементов.
Ответ 18+ 🔞
Ну, вот смотри, тут про forEach в стримах рассказывают, а я тебе на пальцах объясню, чтобы ты не охуел от этой документации.
Представь, что стрим — это конвейер с пивом. Ты его фильтруешь, сортируешь, делаешь с ним что хочешь. А forEach — это момент, когда ты, наконец, этот пивной бокальчик подносишь ко рту и делаешь глоток. Всё, процесс завершён, обратно в конвейер его не засунешь. Это и есть конечная операция, ёпта. После неё поток закрывается нахер.
Вот тебе пример, чтобы не быть голословным:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
.filter(name -> name.startsWith("A"))
.forEach(System.out::println); // Конечная операция
Тут мы отфильтровали имена, и forEach их просто выплюнул в консоль. Всё, приехали.
А теперь главное, что надо запомнить, чтобы не выглядеть как манда с ушами:
- После
forEach— тишина. Попробуй после него вызвать ещё какой-нибудьmapилиfilter— компилятор тебе такую ошибку влепит, что ты сам от себя охуеешь. Поток уже умер, чувак, его не воскресить. - Если работаешь с параллельными стримами (
parallelStream()), то порядок выполнения — как бог на душу положит. Элементы могут обрабатываться в разнобой. Если тебе важен порядок, как в армии, то бериforEachOrdered. Он, правда, может быть медленнее, но зато всё по полочкам. - Сам по себе
forEachне тыкается в исходную коллекцию. Он не удалит оттуда элементы и не добавит новых. Но! Если внутри действия ты, например, вызываешь сеттер у объекта и меняешь его состояние — то да, объект изменится. Это как если бы ты, выпив пиво из кружки, нарисовал на ней усы. Кружка-то та же, но вид другой.
Короче, forEach — это точка, где всё заканчивается. Используй его, когда тебе нужно просто что-то сделать с каждым элементом и забыть. Для всего остального есть другие операции.