Consider the following class:
class Temp { private final int field = 5; int sum() { return 1 + this.field; } }
Then I compile and decompile the class:
> javac --version javac 11.0.5 > javac Temp.java > javap -v Temp.class ... int sum(); descriptor: ()I flags: (0x0000) Code: stack=2, locals=1, args_size=1 0: iconst_1 1: aload_0 2: invokestatic #3 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object; 5: pop 6: iconst_5 7: iadd 8: ireturn
In simple words, javac
compiles sum()
to this:
int sum() { final int n = 1; Objects.requireNonNull(this); // <--- return n + 5; }
What is Objects.requireNonNull(this)
doing here? What's the point? Is this somehow connected to reachability?
The Java 8 compiler is similar. It inserts this.getClass()
instead of Objects.requireNonNull(this)
:
int sum() { final int n = 1; this.getClass(); // <--- return n + 5; }
I also tried to compile it with Eclipse. It doesn't insert requireNonNull
:
int sum() { return 1 + 5; }
So this is javac-specific behavior.
requireNonNull. Checks that the specified object reference is not null and throws a customized NullPointerException if it is. Unlike the method requireNonNull(Object, String) , this method allows creation of the message to be deferred until after the null check is made.
The nonNull method is a static method of the Objects class in Java that checks whether the input object reference supplied to it is non-null or not. If the passed object is non-null, then the method returns true. If the passed object is null , then the method returns false.
Since the field is not only final
, but a compile-time constant, it will not get accessed when being read, but the read gets replaced by the constant value itself, the iconst_5
instruction in your case.
But the behavior of throwing a NullPointerException
when dereferencing null
, which would be implied when using a getfield
instruction, must be retained¹. So when you change the method to
int sumA() { Temp t = this; return 1 + t.field; }
Eclipse will insert an explicit null check too.
So what we see here, is javac
failing to recognize that in this specific case, when the reference is this
, the non-null property is guaranteed by the JVM and hence, the explicit null check is not necessary.
¹ see JLS §15.11.1. Field Access Using a Primary:
If the field is not
static
:
- The Primary expression is evaluated. If evaluation of the Primary expression completes abruptly, the field access expression completes abruptly for the same reason.
- If the value of the Primary is
null
, then aNullPointerException
is thrown.- If the field is a non-blank
final
, then the result is the value of the named member field in typeT
found in the object referenced by the value of the Primary.…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With