Могу ли я сказать, что метод 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() не является идемпотентным, поскольку каждый вызов создает новую строку вывода.

Другие вопросы по тегам