Search code examples
javalambdajava-8conceptual

Why aren't method references singleton?


In Java, the following code returns false on both queries. Why? Wouldn't it be simpler for method references to be singleton? It would certainly make attaching and detaching listeners a lot simpler. As it is you need to keep a constant for any method reference that will need to be equivalence checked, you can't just use the method reference operator at every necessary location.

public class Main {

    public Main() {
        // TODO Auto-generated constructor stub
    }

    public void doStuff() {

    }

    public static void main(String[] args) {
        Main main = new Main();
        Runnable thing1 = main::doStuff;
        Runnable thing2 = main::doStuff;
        System.out.println(thing1 == thing2); // false
        System.out.println(thing1.equals(thing2)); // false
    }

}

Solution

  • For instance methods, I don't think it would make sense for them to be cached. You'd have to cache one method per instance... which would either mean an extra field within the class associated with the method - one per public method, presumably, because the methods could be referenced from outside the class - or cached within the user of the method reference, in which case you'd need some sort of per-instance cache.

    I think it makes more sense for method references to static methods to be cached, because they'll be the same forever. However, to cache the actual Runnable, you'd need a cache per type that it was targeting. For example:

    public interface NotRunnable {
        void foo();
    }
    
    Runnable thing1 = Main::doStuff; // After making doStuff static
    NotRunnable thing2 = Main::doStuff;
    

    Should thing1 and thing2 be equal here? How would the compiler know what type to create, if so? It could create two instances here and cache them separately - and always cache at the point of use rather than the point of method declaration. (Your example has the same class declaring the method and referencing it, which is a very special case. You should consider the more general case where they're different>)

    The JLS allows for method references to be cached. From section 15.13.3:

    Next, either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced.

    ... but even for static methods, it seems javac doesn't do any caching at the moment.