2

I have some confusion and want to clear my concept.

Let say we the following statement:

.map(i -> Tests.doubleIt(i))

So, when using the :: as:

.map(Tests::doubleIt)

So, do the i parameter is internally received by the doubleIt and internally passed to doubleIt method?

Can we know the internals how the i is received and passed to the doubleIt method in case of ::?

  • I'm not sure what you mean by "internally received". But `map` expects the input of exactly *one* argument, and the return of a certain type. By writing `Tests::doubleIt` the compiler searches for a method with the name `doubleIt` within `Tests` which accepts *one* argument and returns a certain type. – MC Emperor Dec 23 '18 at 11:29
  • https://stackoverflow.com/a/20001866/7972699 read this will help – Anmol Dec 23 '18 at 11:31

3 Answers3

3

The code in map calls the function you pass it (doubleIt) passing it the argument directly, which doubleIt receives as its first formal parameter. In contrast, with your lambda version, map calls your lambda with the argument, which your lambda receives as its i parameter, and then your lambda calls doubleIt using i as the argument. So it's more direct with the method reference (in theory) than with the lambda.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • What if we have more that one parameters? –  Dec 23 '18 at 11:25
  • 1
    @user10796624 - It's exactly the same situation. The method you pass in must match what `map` is expecting (in `map`'s case, a method with a single formal parameter of type `int` [if I'm not mistaken]). But if you're calling a method that expects a callback that accepts multiple parameters, then of course when it calls that method, it will pass it multiple arguments, one for each parameter. – T.J. Crowder Dec 23 '18 at 11:27
  • and all the multiple parameters will be placed into their own places for example `p1`, `p1`, `p3` will be `doubleIt(p1,p2,p3)`, is i am correct? –  Dec 23 '18 at 11:30
  • 1
    @user10796624 - Of course. It's just a method call. There's nothing special about it. – T.J. Crowder Dec 23 '18 at 11:31
1

So, do the i parameter is internally received by the doubleIt and internally passed to doubleIt method?

.map(i -> Tests.doubleIt(i))

the above line reads as "given an element represent as i, call the doubleIt method with the current element as input".

In other words, you're specifying the "what" should be done and the "how" it should be done is an internal implementation detail.

Can we know the internals how the i is received and passed to the doubleIt method in case of ::?

When you pass Tests::doubleIt you're essentially passing a "reference" to the doubleIt method and for each element of the source the map method will invoke the doubleIt function passing the current element as input.

There's nothing more to it.

Readings you may find useful:

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • And all this is done `internally`, no need to do extra work for it, right? –  Dec 23 '18 at 11:27
  • @user10796624 yes, the main idea of functional programming as of JDK8 is the user only specifies the "what" and the "how" is an internal implementation detail. – Ousmane D. Dec 23 '18 at 11:29
  • @user10796624 you're welcome. added some few blogs which you might find useful. all the best :) – Ousmane D. Dec 23 '18 at 11:42
0

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.

ernest_k
  • 44,416
  • 5
  • 53
  • 99