Могу ли я сказать, что метод peek() в java.util.stream.Stream должен быть идемпотентным
Мой вопрос связан с: что означает идемпотентный метод и каковы побочные эффекты в случае вызова метода close из java.lang.AutoCloseable?
Что касается метода в java.util.stream.Stream.peek()
В книге Oracle Certified Professional Java SE 8 Учебное пособие> глава 4 Функциональное программирование> Использование потоков> Использование общих промежуточных операций было указано, что peek() предназначен для выполнения операции без изменения результата.
У меня такой вопрос: могу ли я сказать на практике, что действие в процессе просмотра (действие потребителя) должно быть идемпотентным, даже если код с состоянием в peek()
можно скомпилировать?
2 ответа
Вы не должны этого делать, потому что это может означать, что операция может изменить конечный результат, потому что идемпотентная операция может изменить объект, с которым она работает.
В следующем примере используется идемпотентная операция внутри peek()
метод, но меняет результат (что не является хорошей практикой в соответствии с документацией, которую вы указали)
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class SomeClass {
private String state = "some-value";
public void idempotent() {
state = "other-value";
}
@Override
public String toString() {
return "SomeClass{" +
"state='" + state + '\'' +
'}';
}
}
public class Idempotent {
public static void main(String[] args) {
Set<SomeClass> collect = Stream.of(new SomeClass(), new SomeClass())
.peek(SomeClass::idempotent)
.collect(Collectors.toSet());
System.out.println(collect);
}
}
Перед peek()
операция поток состоит из ["some-value", "some-value]
и после peek()
с идемпотентной операцией он состоит из ["other-value", "other-value"]
,
В Javadoc говорится, что он должен быть не мешающим, а не идемпотентным, что не одно и то же.
На самом деле, поскольку он должен быть не мешающим и может действовать только через побочные эффекты, вполне вероятно, что он не идемпотентен.
В примечании API даже ясно показан пример неидемпотентного использования:
Этот метод существует главным образом для поддержки отладки, где вы хотите видеть элементы, проходящие мимо определенной точки в конвейере:
Stream.of("one", "two", "three", "four") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList());
Как Вам известно, System.out.println()
не является идемпотентным, поскольку каждый вызов создает новую строку вывода.