0

My question is related to: What does idempotent method mean and what are the side effects in case of calling close method of java.lang.AutoCloseable?

As to the method in java.util.stream.Stream.peek(), in the book Oracle Certified Professional Java SE 8 Study Guide > chapter 4 Functional programming > Using Streams > Using Common Intermediate Operations, it was stated that peek() is intended to perform an operation without changing the result

My question is: can I say in practice, the action in peek(Consumer action) should be idempotent even though the stateful code in peek() can compile?

Rui
  • 3,454
  • 6
  • 37
  • 70
  • You can say that the `peek` method should be idempotent. There's no guarantees about the action being called is, though perhaps you're right. It *should* be idempotent, there's' just no guarantee that it will be. – Lasse V. Karlsen Apr 28 '18 at 22:03
  • Great! Thanks a lot @LasseVågsætherKarlsen, if you write down the answer I would check :) – Rui Apr 28 '18 at 22:05
  • To be honest, I'd rather not. I'm no java expert and your question implies "should" which could be construed as a matter of opinion. If my comment helped you, great! But I'll defer to greater (java) minds to actually post an answer. – Lasse V. Karlsen Apr 28 '18 at 22:06

2 Answers2

0

You shouldn't because that would imply that the operation can change the final result because an idempotent operation can mutate the object it operates on.

The following example uses an idempotent operation inside the peek() method but changes the result (which is not a good practice according to the documentation you pointed out)

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);
    }
}

Before the peek() operation the stream is composed of ["some-value", "some-value] and after the peek() with an idempotent operation it's composed of ["other-value", "other-value"].

fabiim
  • 825
  • 2
  • 9
  • 18
  • Of course `peek()` can change the state of an object, but I mean that *it should not* The example you gave can compile, but that is no doubt a bad practice – Rui Apr 28 '18 at 22:45
0

The Javadoc says that it should be non-interfering, not idempotent, which is not the same thing.

In fact, since it must be non-interfering and can only operate via side-effects, it is likely that it is not idempotent.

The API note even clearly shows a non-idempotent usage example:

This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline:

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());

As you know, System.out.println() is not idempotent since each call produces a new line of output.

Didier L
  • 18,905
  • 10
  • 61
  • 103