It gets simpler when you consider the functional interface type and the stream value itself in isolation.
On the one hand, Suppose a simplistic custom class that holds an integer and has a map
method:
class MyObject {
int value = 0;
MyObject map(Function<Integer, Integer> f) {
this.value = f.apply(this.value);
return this;
}
}
This MyObject
class knows the element it holds, so when its map
method is executed, the class knows where to find the value that the function will take as parameter. Roughly speaking, this is also how streams use the function.
On the other hand, there's the creation of a Function<Integer, Integer>
instance that will be passed to map
.
As you pointed out, you can use Tests::doubleIt
or i -> Tests.doubleIt(i)
to supply the argument to map
(in this case, it doesn't matter which method, the resulting Function
object will be called in the same way).
What I'm trying to get at: these are two are separate concerns: MyObject
will know how to source the elements passed to Function.apply
while the class calling map
will be responsible for supplying the logic. This "logic" is the Function
instance.
When you look at the two in isolation, the answer to your question becomes obvious. I believe it will help to implement similar code.