It was very confusing to me to observe this situation:
Integer i = null; String str = null; if (i == null) { //Nothing happens ... } if (str == null) { //Nothing happens } if (i == 0) { //NullPointerException ... } if (str == "0") { //Nothing happens ... }
So, as I think boxing operation is executed first (i.e. java tries to extract int value from null
) and comparison operation has lower priority that's why the exception is thrown.
The question is: why is it implemented in this way in Java? Why boxing has higher priority then comparing references? Or why didn't they implemented verification against null
before boxing?
At the moment it looks inconsistent when NullPointerException
is thrown with wrapped primitives and is not thrown with true object types.
In Java, int is a primitive data type while Integer is a Wrapper class. int, being a primitive data type has got less flexibility. We can only store the binary value of an integer in it. Since Integer is a wrapper class for int data type, it gives us more flexibility in storing, converting and manipulating an int data.
Integer. equals() method compares this object to the specified object. The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object.
Some int value as an int? is definitely non-null and null is definitely null. The compiler realizes that and since a non-null value is not equal to a definite null value, the warning is given. The compiler also optimizes this away because it is always false. It won't even load the x variable at all.
What Causes NullPointerException. The NullPointerException occurs due to a situation in application code where an uninitialized object is attempted to be accessed or modified. Essentially, this means the object reference does not point anywhere and has a null value.
Your NPE example is equivalent to this code, thanks to autoboxing:
if ( i.intValue( ) == 0 )
Hence NPE if i
is null
.
The key point is this:
==
between two reference types is always reference comparison Integer
and String
, you'd want to use equals
instead==
between a reference type and a numeric primitive type is always numeric comparison null
always throws NullPointerException
String
, it is in fact NOT a primitive typeThe above statements hold for any given valid Java code. With this understanding, there is no inconsistency whatsoever in the snippet you presented.
Here are the relevant JLS sections:
JLS 15.21.3 Reference Equality Operators
==
and!=
If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.
This explains the following:
Integer i = null; String str = null; if (i == null) { // Nothing happens } if (str == null) { // Nothing happens } if (str == "0") { // Nothing happens }
Both operands are reference types, and that's why the ==
is reference equality comparison.
This also explains the following:
System.out.println(new Integer(0) == new Integer(0)); // "false" System.out.println("X" == "x".toUpperCase()); // "false"
For ==
to be numerical equality, at least one of the operand must be a numeric type:
JLS 15.21.1 Numerical Equality Operators
==
and!=
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible to numeric type, binary numeric promotion is performed on the operands. If the promoted type of the operands is
int
orlong
, then an integer equality test is performed; if the promoted type isfloat or
double`, then a floating-point equality test is performed.Note that binary numeric promotion performs value set conversion and unboxing conversion.
This explains:
Integer i = null; if (i == 0) { //NullPointerException }
Here's an excerpt from Effective Java 2nd Edition, Item 49: Prefer primitives to boxed primitives:
In summary, use primitives in preference to boxed primitive whenever you have the choice. Primitive types are simpler and faster. If you must use boxed primitives, be careful! Autoboxing reduces the verbosity, but not the danger, of using boxed primitives. When your program compares two boxed primitives with the
==
operator, it does an identity comparison, which is almost certainly not what you want. When your program does mixed-type computations involving boxed and unboxed primitives, it does unboxing, and when your program does unboxing, it can throwNullPointerException
. Finally, when your program boxes primitive values, it can result in costly and unnecessary object creations.
There are places where you have no choice but to use boxed primitives, e.g. generics, but otherwise you should seriously consider if a decision to use boxed primitives is justified.
Integer
to type int
"r
is null
, unboxing conversion throws a NullPointerException
"==
and !=
==
and !=
Integers
in Java does auto-unboxing occur?==
but not equals()
?int num = Integer.getInteger("123")
throw NullPointerException
? (!!!)String.equals
versus ==
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