4

Is it possible to do something like:

boolean isItMyMethod( Consumer<Object> aConsumer )
{
    return aConsumer.equals( this::myMethod );
}

This does not compile. It does if I assign this::myMethod to an intermediary variable, but then the result is always false.

Jeffrey Bosboom
  • 13,313
  • 16
  • 79
  • 92
amynbe
  • 501
  • 7
  • 12
  • what is the type of myMethod? – Utsav Dawn Feb 26 '15 at 16:25
  • What is the use case ? – gontard Feb 26 '15 at 16:29
  • Why do you want to do that? BTW directly passing method reference won't work because target type of lambdas and method references should be a Functional Interface, and `Object` is not that. – Rohit Jain Feb 26 '15 at 16:38
  • 2
    You can't rely on `.equals` on lambdas or method references to return consistent results, anyway. – Jeffrey Bosboom Feb 26 '15 at 17:03
  • 2
    Or, in other words, with the current implementation, you can say `Consumer c1=this::myMethod, c2=this::myMethod;` and both, `c1==c2` or `c1.equals(c2)`, will evaluate to `false`. So you can fix your code to `aConsumer.equals((Consumer) this::myMethod )` but it will always yield `false` (with the current JRE implementation). See also http://stackoverflow.com/q/28190304/2711488 – Holger Feb 26 '15 at 17:37

1 Answers1

5

The target type for a method reference, or a lambda, should be a functional interface. Since equals() method takes an Object, which is not a functional interface, it fails to compile. Now you would say, why? Well, a lambda expression or a method reference is at runtime implemented as an instance of a class implementing that functional interface. A FI contains just a single abstract method, thus for a lambda x -> Sysout(x), the left part becomes the parameter of that method, and right part becomes body.

Now there can be many functional interface, providing such method signature. That means same lambda expression can be compiled to implementation of different FIs. Now when you pass a lambda to an Object reference like this:

Object ob = x -> Sysout(x);

which FI do you expect JVM to instantiate? This results in certain ambiguity, and hence is not allowed. But by pre-assigning a lambda to a FI reference:

Consumer<Object> consumer = x -> Sysout(x);

you've assigned a concrete meaning to the lambda, which then later on can be assigned to any of its super type reference.

Object ob = consumer;

Now as for why equals() method returns false, you can guess it. Since lambda is an instance of a class constructed at runtime, which would provide implementation of the abstract method in FI, on what basis would you want two Consumer references to compare? Since there is no equals() method overridden, it will invoke the implementation in Object class, which just compares the reference. Implementation looks like this:

public boolean equals(Object ob) {
    return this == ob;
}

Certainly aConsumer == bConsumer will return false, if both are referring to 2 different lambdas / method references.

Rohit Jain
  • 209,639
  • 45
  • 409
  • 525