Why can method reference use non-final variables?

A method reference is not a lambda expression, although they can be used in the same way. I think that is what is causing the confusion. Below is a simplification of how Java works, it is not how it really works, but it is close enough.

Say we have a lambda expression:

Runnable f = () -> one.bar();

This is the equivalent of an anonymous class that implements Runnable:

Runnable f = new Runnable() {
    public void run() {
       one.bar();
    }
}

Here the same rules apply as for an anonymous class (or method local class). This means that one needs to effectively final for it to work.

On the other hand the method handle:

Runnable f = one::bar;

Is more like:

Runnable f = new MethodHandle(one, one.getClass().getMethod("bar"));

With MethodHandle being:

public class MethodHandle implements Runnable {
    private final Object object;
    private final Method method;

    public MethodHandle(Object object, java.lang.reflect.Method method) {
        this.object = Object;
        this.method = method;
    }

    @Override
    public void run() {
        method.invoke(object);
    }
}

In this case, the object assigned to one is assigned as part of the method handle created, so one itself doesn’t need to be effectively final for this to work.

Leave a Comment