Search code examples
javajava-8instancefunctional-interfacesupplier

Method reference does not always seem to capture instance


I know there are many questions on the subject even a very recent one but I still can't work my head around one thing. Consider the following functional interface:

@FunctionalInterface
interface PersonInterface {
    String getName();
}

And this implementation:

class Person implements PersonInterface {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

If I look at these threads 1 and 2, I expect the following code to output "Bob" and not throw a NullPointerException because as far as I understand, when I create my Supplier, it captures the Person instance.

Person p = new Person("Bob");
Supplier<String> f = p::getName;
p = null;
System.out.println(f.get());

And it correctly outputs "Bob"

Now what I do not understand is why the following code does not also output "Bob"?

Person p = new Person("Bob");
Supplier<String> f = p::getName;
p.setName("Alice");
System.out.println(f.get());

It actually outputs "Alice"

It seems to me that in the first example the lambda captured the state of the Person object when it was created and does not try to re-evaluate it when it is called, when in the second case, it seems like it did not capture it, but revaluates it when it is called.

EDIT After re-reading the other threads and with Eran's answer, I wrote that bit with 2 Persons pointing to the same instance:

Person p1 = new Person("Bob");
Person p2 = p1;
Supplier<String> f1 = p1::getName;
Supplier<String> f2 = p2::getName;
p1 = null;
p2.setName("Alice");
System.out.println(f1.get());
System.out.println(f2.get());

Now I can see that they both output "Alice" even though p1 is null and therefore the method reference captured the instance itself, not its state as I wrongly assumed.


Solution

  • It seems to me that in the first example the lambda captured the state of the Person object when it was created and does not try to re-evaluate it when it is called, when in the second case, it seems like it did not capture it, but revaluates it when it is called.

    First of all, it's a method reference, not a lambda expression.

    In both cases a reference to the Person instance is captured by the method reference (which is not "the state of the Person object"). That means that if the state of the Person instance is mutated, the result of executing the functional interface's method may change.

    The method reference does not create a copy of the Person instance whose reference it captures.