When instance-bound method reference is compiled, javac adds a null-check into the code. In Java 8 it's getClass() call, in Java 9 it's Objects.requireNonNull() call (JDK-8073432). However in both cases the line number associated with this call is not the line number where method reference qualifier appears, but the line number of the previously generated code. This leads to confusing stack traces when NPE is thrown. For example, consider the following code:
1. package test;
2.
3. import java.util.function.Supplier;
4.
5. public class Test {
6. public static void main(String[] args) {
7. String str = null;
8.
9. Supplier<String> s =
10.
11. str::trim;
12. }
13.}
When compiled and launched it throws in Java-8 (testing 8u101):
Exception in thread "main" java.lang.NullPointerException
at test.Test.main(Test.java:9)
In Java-9 (testing build 139):
Exception in thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull(java.base@9-ea/Objects.java:221)
at test.Test.main(Test.java:9)
I expect that it should report an exception in line 11, where the qualified appears, not the line 9.
Here's javap output for the main method (using java 9 javac):
Code:
stack=2, locals=3, args_size=1
0: aconst_null
1: astore_1
2: aload_1
3: dup
4: invokestatic #2 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
7: pop
8: invokedynamic #3, 0 // InvokeDynamic #0:get:(Ljava/lang/String;)Ljava/util/function/Supplier;
13: astore_2
14: return
LineNumberTable:
line 7: 0
line 9: 2
line 12: 14
I would expect having "line 11: 4" in the LineNumberTable.
1. package test;
2.
3. import java.util.function.Supplier;
4.
5. public class Test {
6. public static void main(String[] args) {
7. String str = null;
8.
9. Supplier<String> s =
10.
11. str::trim;
12. }
13.}
When compiled and launched it throws in Java-8 (testing 8u101):
Exception in thread "main" java.lang.NullPointerException
at test.Test.main(Test.java:9)
In Java-9 (testing build 139):
Exception in thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull(java.base@9-ea/Objects.java:221)
at test.Test.main(Test.java:9)
I expect that it should report an exception in line 11, where the qualified appears, not the line 9.
Here's javap output for the main method (using java 9 javac):
Code:
stack=2, locals=3, args_size=1
0: aconst_null
1: astore_1
2: aload_1
3: dup
4: invokestatic #2 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
7: pop
8: invokedynamic #3, 0 // InvokeDynamic #0:get:(Ljava/lang/String;)Ljava/util/function/Supplier;
13: astore_2
14: return
LineNumberTable:
line 7: 0
line 9: 2
line 12: 14
I would expect having "line 11: 4" in the LineNumberTable.