6

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?

4
  • What is the call stack of NPE? What exactly is null? Commented Nov 5, 2015 at 20:51
  • 2
    this bug report looks relevant: bugs.openjdk.java.net/browse/JDK-8131323 Commented Nov 5, 2015 at 20:53
  • 5
    controller::writeReport throw an NPE? because controller is null. You are trying to reference a method on a null object -> NPE. Commented Nov 5, 2015 at 20:58
  • Note that this runs without an NPE when compiled with Eclipse 4.4.1! Commented Nov 27, 2015 at 23:20

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

This is more obvious if you write the lambda as () -> 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.
3

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.