Могу ли я сказать, что метод peek() в java.util.stream.Stream должен быть идемпотентным?

Мой вопрос связан с: Что означает идемпотентный метод и каковы побочные эффекты в случае вызова метода close java.lang.AutoCloseable?

Что касается метода в java.util.stream.Stream.peek(), в книге Oracle Certified Professional Java SE 8 Study Guide > глава 4 Функциональное программирование > Использование потоков > Использование общих промежуточных операций было указано, что peek() предназначен для выполнения операции без изменения результат

Мой вопрос таков: могу ли я сказать, что на практике действие в peek(Consumer action) должно быть идемпотентным, даже если код с сохранением состояния в peek() может компилировать?


person Rui    schedule 28.04.2018    source источник
comment
Можно сказать, что метод peek должен быть идемпотентным. Нет никаких гарантий, что вызываемое действие есть, хотя, возможно, вы правы. Он должен быть идемпотентным, просто нет никакой гарантии, что это будет так.   -  person Lasse V. Karlsen    schedule 29.04.2018
comment
Здорово! Большое спасибо @LasseVågsætherKarlsen, если вы запишите ответ, я бы проверил :)   -  person Rui    schedule 29.04.2018
comment
Честно говоря, я бы не хотел. Я не эксперт по Java, и ваш вопрос подразумевает, что это может быть истолковано как мнение. Если мой комментарий помог вам, отлично! Но я уступлю лучшим (java) умам, чтобы опубликовать ответ.   -  person Lasse V. Karlsen    schedule 29.04.2018


Ответы (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"].

person fabiim    schedule 28.04.2018
comment
Конечно, peek() может изменить состояние объекта, но я имею в виду, что это не должно Пример, который вы привели, может компилироваться, но это, несомненно, плохая практика. - person Rui; 29.04.2018

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

person Didier L    schedule 15.05.2018