peek выглядит удобным способом вставить действие внутрь stream pipeline. Часто туда кладут логирование, метрики или даже изменение объекта.
Например, такой код кажется коротким:
users.stream()
.peek(User::activate)
.toList();
Проблема в том, что peek задуман как инструмент для отладки и наблюдения за элементами, а не как основной шаг бизнес-логики.
Пока нет terminal operation, ничего не выполняется:
users.stream()
.peek(User::activate);
В этом примере activate вообще не вызовется, потому что pipeline только описан, но не запущен.
Ещё хуже, когда поведение зависит от terminal operation. Например, count может быть оптимизирован так, что часть промежуточных действий не выполняется ожидаемым способом.
Если нужно изменить объекты явно, лучше использовать обычный цикл:
for (User user : users) {
user.activate();
}Если нужно получить новые значения, лучше использовать map:
List result = users.stream()
.map(UserDto::from)
.toList();
А peek оставить для временной диагностики:
users.stream()
.peek(user -> log.debug("user {}", user.id()))
.toList();
👉 Java Ready | #совет
