Friday 4 May 2018

Creating a method reference on a null reference does not throw NullPointerException

We ran into a problem that the Unit tests ran perfectly on my local machine, but the same Unit tests would break in the continuous delivery pipeline.

The problem occurred when creating a method reference. Like so:

When running the test included above, the test failed with:

java.lang.AssertionError: Expected exception: java.lang.NullPointerException

After some research we found out that the difference between the two is the Eclipse compiler used by the IntelliJ IDE vs. the openjdk installed in the continuous delivery pipeline.

We found out that it is illegal to use a method reference on a null reference. Quoting from [1]:

First, if the method reference expression begins with an ExpressionName or a Primary, this subexpression is evaluated. If the subexpression evaluates to null, a NullPointerException is raised, and the method reference expression completes abruptly.

At first glance, this is a bit weird. After all, we want to have a method reference, in order to call it at a later time, which in fact may never occur. So why not have the NullPointerException when an attempt is made to actually call the method?

IntelliJ

IntelliJ comes equipped automatically with the Eclipse Java Compiler (ECJ), and as such it takes some effort to find out which version is installed along with the IDE.

Jar file ecj-4.6.1.jar was include in directory .local/share/JetBrains/Toolbox/apps/IDEA-U/ch-1/181.4445.78/lib/ecj-4.6.1.jar.

In IntelliJ it is possible to provide the path to the ecj jar to use, see [2].

Setting the path to the newly downloaded jar file ~/Downloads/ecj-4.7.3a.jar solved my problem.

It's been a long time since I encountered a bug in the compiler3, but other people have noticed it too4 and then it gets fixed.

Note

Bear in mind that, if we did not use a method reference, but an ordinary lambda, that this problem would not have occurred (immediately).

This means that, if you replace a Lambda with a method reference you may be introducing a NullPointerException earlier in the code without realising it5.

Bear this in mind.

References

[1] JLS 8 - 15.13.3. Run-Time Evaluation of Method References
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13.3
[2] IntelliJ - Specifying compilation settings
https://www.jetbrains.com/help/idea/specifying-compilation-settings.html
[3] Eclipse - Bug Report
https://bugs.eclipse.org/bugs/show_bug.cgi?id=521182
[4] StackOverflow - Creating a method reference on a null reference does not throw an exception
https://stackoverflow.com/questions/37681625/creating-a-method-reference-on-a-null-reference-does-not-throw-an-exception
[5] StackOverflow - java.lang.NullPointerException is thrown using a method reference but not a lambda
https://stackoverflow.com/questions/37413106/java-lang-nullpointerexception-is-thrown-using-a-method-reference-but-not-a-lamb/37413546

No comments:

Post a Comment