Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Java method references stable? [duplicate]

Tags:

If I obtain a method reference using the new syntax:

anObject::aMethod 

Do I always get the same object? That is, can I trust that two references to the same method will be equal?

This is good to know if, for example, I plan to use them as Runnable callbacks that I can add and remove:

someLibrary.addCallback(anObject::aMethod) // later someLibrary.removeCallback(sameObject::sameMethod) 

Would this require saving the reference in a Runnable variable to keep it stable?

like image 390
slezica Avatar asked Jun 07 '18 19:06

slezica


People also ask

What is the advantage of method reference in Java 8?

That's all about what is method reference is in Java 8 and how you can use it to write clean code in Java 8. The biggest benefit of the method reference or constructor reference is that they make the code even shorter by eliminating lambda expression, which makes the code more readable.

Why method reference is better than lambda?

The method references can only be used to replace a single method of the lambda expression. A code is more clear and short if one uses a lambda expression rather than using an anonymous class and one can use method reference rather than using a single function lambda expression to achieve the same.

Does it make sense to replace lambda expressions with method references?

If you have been coding in Java 8 then you may know that using method reference in place of lambda expression makes your code more readable, hence it is advised to replace lambda expression with method reference wherever possible.

WHAT ARE method references and how are they useful in Java?

Method references are a special type of lambda expressions. They're often used to create simple lambda expressions by referencing existing methods. There are four kinds of method references: Static methods. Instance methods of particular objects.


2 Answers

JLS makes no promises about identity or equality of what you get out of method reference expressions.

You can run a quick test:

Object obj = new Object();  IntSupplier foo = obj::hashCode; IntSupplier bar = obj::hashCode;  System.out.println(foo == bar);  // false  System.out.println(foo.equals(bar));  // false       

But this is, of course, implementation dependent.

You could make your lambda Serializable and key your callback map with the serlialized representation. See How to serialize a lambda?. While this will work, it's not exactly required to work by the specs.

like image 166
Misha Avatar answered Oct 06 '22 01:10

Misha


Just try this out to get the answer:

Object object = ...; Supplier<String> s1 = object::toString; Supplier<String> s2 = object::toString; System.out.println(s1.equals(s2)); 

And the answer is... unfortunately not.

OF course if you keep the same reference (i.e. the same object), it will work; but if, as the example above, you request two lambdas, although they seem to be identical, they will never be equal. Therefore reference = object::methodand then later remove(reference) will obviously work, but remove(sameObject::sameMethod) from a collection will never work if it is written literaly as such.

The answer is also no for constructor (e.g. ArrayList::new) and unbound methods (e.g. Object::toString). It seems that a new lambda is constructed each time you use a lambda expression.

As @Hitobat points it out, this unequality makes sense if you think about what exactly are lambdas and where do they come from. Basicly, Supplier<String> x = myObject::toString is a syntactic suggar for Supplier<String> x = new Supplier<String>( ... ). Without a proper Object.equals overloading, two instances of an anonymous class are obviously different. As many people probably, I though that there was a kind of cache of frequently used lambdas somewhere to make it more efficient; well, not at all.

like image 31
QuentinC Avatar answered Oct 06 '22 01:10

QuentinC