jheyd
jheyd

Reputation: 599

Java method reference throws NPE

So I got a class

public class MenuBar extends JMenuBar {

    MenuBarController controller;

    public MenuBar() {
        JMenu menu = new JMenu("File");
        menu.add(createMenuItem("Report", controller::writeReport));
        menu.add(createMenuItem("Save", controller::save));
        menu.add(createMenuItem("Import", controller::importFile));
        menu.add(createMenuItem("Clear DB", controller::clearDatabase));
        add(menu);
    }

    public void setController(MenuBarController controller) {
        this.controller = controller;
    }
}

MenuBarController is an interface whose implementation is set via setController after the MenuBar ist created. The code throws a NullpointerException at menu.add(createMenuItem("Report", controller::writeReport)) which can only be caused by controller::writeReport. If I replace this with a lambda like () -> controller.writeReport() no NPE is thrown.

1. Why does controller::writeReport throw an NPE?

2. Why doesn't the lambda throw an NPE?

The funny part is: If I replace the lambda with the method reference used before after I ran it once with the lambda, no more NPEs are thrown.

Anyone got any idea why that could be? Some javac / eclipse weirdness?

Upvotes: 6

Views: 547

Answers (2)

Ian McLaird
Ian McLaird

Reputation: 5585

controller::writeReport throws an NPE because controller is null when the line is evaluated.

() -> controller.writeReport() does not throw an NPE because by the time the lambda is run, controller has been given a value.

Upvotes: 3

jheyd
jheyd

Reputation: 599

https://bugs.openjdk.java.net/browse/JDK-8131323 explains why that happens. Method references work differently from lambdas, the method reference (not the method itself) is not evaluated lazily as it would be in a lambda.

Upvotes: 3

Related Questions