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?
2 Answers 2
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.
1 Comment
() -> this.controller.writeReport(), with an explicit receiver (which is what the lambda means anyway). Then it becomes easier to see that the lambda is capturing this, not controller, which is why the two behave differently.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.
controller::writeReport throw an NPE?becausecontrolleris null. You are trying to reference a method on a null object -> NPE.