Предположим, у меня есть поток вещей, и я хочу «обогатить» их серединой потока, я могу использовать peek()
это, например:
streamOfThings.peek(this::thingMutator).forEach(this::someConsumer);
Предположим, что изменение объектов в этой точке в коде является правильным поведением - например, thingMutator
метод может установить в поле «lastProcessed» текущее время.
Однако peek()
в большинстве случаев означает «смотри, но не трогай».
Пользуемся peek()
для мутировать элементы потока в антипаттернах или опрометчиво?
Редактировать:
Альтернативный, более традиционный подход заключается в том, чтобы преобразовать потребителя:
private void thingMutator(Thing thing) {
thing.setLastProcessed(System.currentTimeMillis());
}
к функции, которая возвращает параметр:
private Thing thingMutator(Thing thing) {
thing.setLastProcessed(currentTimeMillis());
return thing;
}
и используйте map()
вместо этого:
stream.map(this::thingMutator)...
Но это вводит небрежный код ( return
), и я не уверен, что он понятнее, потому что, как вы знаете, peek()
возвращает тот же объект, но с первого map()
взгляда даже не ясно, что это тот же класс объекта.
Кроме того, у peek()
вас может быть лямбда, которая мутирует, но с map()
вами придется строить крушение поезда. Для сравнения:
stream.peek(t -> t.setLastProcessed(currentTimeMillis())).forEach(...)
stream.map(t -> {t.setLastProcessed(currentTimeMillis()); return t;}).forEach(...)
Я думаю, что peek()
версия более понятна, и лямбда явно мутирует, поэтому нет «таинственного» побочного эффекта. Точно так же, если используется ссылка на метод и название метода явно подразумевает мутацию, это тоже ясно и очевидно.
Что peek()
касается меня , я не уклоняюсь от использования для изменения - я нахожу это очень удобным.
peek
с потоком, который генерирует его элементы динамически? Это все еще работает, или изменения потеряны? Модификация элементов потока звучит для меня ненадежно.
List<Thing> list; things.stream().peek(list::add).forEach(...);
очень удобно. Недавно. Я использовал его , чтобы добавить информацию для публикации: Map<Thing, Long> timestamps = ...; return things.stream().peek(t -> t.setTimestamp(timestamp.get(t))).collect(toList());
. Я знаю, что есть другие способы сделать этот пример, но я сильно упрощаю здесь. Использование peek()
дает более компактный и более элегантный код IMHO. Помимо читабельности, этот вопрос действительно о том, что вы подняли; это безопасно / надежно?
peek
? У меня похожий вопрос по stackoverflow и надеюсь, что вы могли бы посмотреть на него и дать свой отзыв. Спасибо. stackoverflow.com/questions/47356992/…