6

The oracle Java 8 documentation defines 4 types of method references you can use instead of Lambda Expressions. What I am trying to understand is the kind of method reference described as: "Reference to an instance method of an arbitrary object of a particular type " which is written as ContainingType::methodName.

I am not sure if I am missing something, but to me it seems more like: "Reference to the first parameter of the abstract method of the Functional Interface, assuming it is of type ContainingType". I tried to come up with examples where this 'arbitrary object' is the second parameter, but of course it does not compile.

Is there an official reference how this object is resolved by the compiler? Am I correct in my understanding that:

  1. The arbitrary object has to be the 1st parameter of the abstract method of the functional interface.
  2. The signature of the method reference must be the same as that of the abstract method of the functional interface, without the first parameter.

So a functional interface with abstract method A method(B b, C c, D d) can only be passed instance method references x::methodImpl or B::methodImpl. There is no way I can pass C::methodImpl for example, where it would be an instance of class C with its signature A methodImpl(B b, D d).

Are there any other cases I am missing, which might be the reason why Oracle wrote this in such an ambiguous way?

jbx
  • 21,365
  • 18
  • 90
  • 144
  • 2
    `B::methodImpl` references an instance method of arbitrary `b` of type `B`. The arbitrary `b` will be passed to the function as the 1st parameter. – ZhongYu Sep 29 '15 at 23:49
  • What if the instance method in `B` has following signature: `A methodImpl(C c)` (missing the argument D) will it still work, ignoring the last argument of the lambda expression? Like when we do `(B b, C c, D d) -> b.methodImpl(c)` ? Or does the signature have to match exactly? – jbx Sep 30 '15 at 00:36
  • 2
    No. Think of an instance method as a static method, with an extra 1st parameter. So `A methodImpl(C c)` is kind of like `static A methodImpl(B b, C c)`. Therefore reference to this method is compatible with functions of shape `(B,C)->A` – ZhongYu Sep 30 '15 at 01:25

1 Answers1

9

No, your understanding is correct. The documentation you linked implies (but does not adequately emphasize) that given a functional interface that expects args a1, a2, a3, ..., a method reference of this type is equivalent to a lambda that calls a1.namedMethod(a2, a3, ...).

Note that a concrete definition like this is required for consistency's sake - given the example on the linked documentation of a functional interface with two String arguments (String s1, String s2), how would you determine whether the behavior would be s1.doThing(s2) or s2.doThing(s1) otherwise?

You can find this specified precisely in the JLS:

If the compile-time declaration is an instance method, then the arguments to the method invocation expression (if any) are the second and subsequent formal parameters of the invocation method. Otherwise, the arguments to the method invocation expression are the formal parameters of the invocation method.

Sbodd
  • 11,279
  • 6
  • 41
  • 42
  • Thanks for your reply. Yes of course if the method arguments are `(String s1, String s2)` it would match with the first one. But then I started thinking what if the arguments where `(Integer i, String s)`, would it still match a method reference like `String::method` where `method` takes an `(Integer)`? It wasn't clear what 'arbitrary' meant, was it the first that matched the type? Was it the first argument? What if the abstract method had `(a1, a2, a3)` and the method reference had arguments `(a1, a2)`, would it still work, ignoring `a3`? Nothing is mentioned clearly in Oracle's tutorial. – jbx Sep 30 '15 at 00:32
  • Just to clarify the last case, the following lambda expression `(B b, C c, D d) -> b.methodImpl(c)` cannot be replaced by a method reference `B::methodImpl` right? (i.e. the abstract method of the functional interface has 3 parameters, but the method reference has 2, so the last one is just unused). You have to write it in full in this case right? – jbx Sep 30 '15 at 00:41