Why comparing Integer with int can throw NullPointerException in Java?
The Short Answer
The key point is this:
==
between two reference types is always reference comparison- More often than not, e.g. with
Integer
andString
, you'd want to useequals
instead
- More often than not, e.g. with
==
between a reference type and a numeric primitive type is always numeric comparison- The reference type will be subjected to unboxing conversion
- Unboxing
null
always throwsNullPointerException
- While Java has many special treatments for
String
, it is in fact NOT a primitive type
The above statements hold for any given valid Java code. With this understanding, there is no inconsistency whatsoever in the snippet you presented.
The Long Answer
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.
References
- JLS 4.2. Primitive Types and Values
- "The numeric types are the integral types and the floating-point types."
- JLS 5.1.8 Unboxing Conversion
- "A type is said to be convertible to a numeric type if it is a numeric type, or it is a reference type that may be converted to a numeric type by unboxing conversion."
- "Unboxing conversion converts [...] from type
Integer
to typeint
" - "If
r
isnull
, unboxing conversion throws aNullPointerException
"
- Java Language Guide/Autoboxing
- JLS 15.21.1 Numerical Equality Operators
==
and!=
- JLS 15.21.3 Reference Equality Operators
==
and!=
- JLS 5.6.2 Binary Numeric Promotion
Related questions
- When comparing two
Integers
in Java does auto-unboxing occur? - Why are these
==
but notequals()
? - Java: What’s the difference between autoboxing and casting?
Related questions
- What is the difference between an int and an Integer in Java/C#?
- Is it guaranteed that new Integer(i) == i in Java? (YES!!! The box is unboxed, not other way around!)
- Why does
int num = Integer.getInteger("123")
throwNullPointerException
? (!!!) - Java noob: generics over objects only? (yes, unfortunately)
- Java
String.equals
versus==
What is the cleanest way to compare an int with a potentially null Integer in Java?
I try to avoid casts whenever possible, so I'd rather use the following, which also looks nicer in my opinion:
Integer.valueOf(8).equals(m.get("null"))
Why do I get NullPointerException when my Integer[] has already been initialized?
You have created the array with
Integer[] numbers = new Integer[input.toString().length()];
Integer
is an object type, so all the values in the array start off as null. If it were int
, then it would be an array of primitives, which would all be initialized to 0.
As you want to update the array value try
for (int x = 0; x < numbers.length; x++) {
numbers [x] = value; // whatever
}
How to compare Integer with int?
Simplest solution I see is to swap your ternary to the assignment of val
(and you might as well use int
). Also, I would prefer Map.getOrDefault(Object, V)
. Like,
int val = 1 + tmap.getOrDefault(key, 0);
tmap.put(key, val);
if (val > maxVal) {
maxVal = val;
maxKey = key;
}
Otherwise, you could repeat the ternary in your comparison (but I personally think that's ugly so I'll leave it as a completely optional exercise for the reader).
Why does int num = Integer.getInteger(123) throw NullPointerException?
The Big Picture
There are two issues at play here:
Integer getInteger(String)
doesn't do what you think it does- It returns
null
in this case
- It returns
- the assignment from
Integer
toint
causes auto-unboxing- Since the
Integer
isnull
,NullPointerException
is thrown
- Since the
To parse (String) "123"
to (int) 123
, you can use e.g. int Integer.parseInt(String)
.
References
- Java Language Guide/Autoboxing
Integer
API references
static int parseInt(String)
static Integer getInteger(String)
On Integer.getInteger
Here's what the documentation have to say about what this method does:
public static Integer getInteger(String nm)
: Determines the integer value of the system property with the specified name. If there is no property with the specified name, if the specified name is empty ornull
, or if the property does not have the correct numeric format, thennull
is returned.
In other words, this method has nothing to do with parsing a String
to an int/Integer
value, but rather, it has to do with System.getProperty
method.
Admittedly this can be quite a surprise. It's unfortunate that the library has surprises like this, but it does teach you a valuable lesson: always look up the documentation to confirm what a method does.
Coincindentally, a variation of this problem was featured in Return of the Puzzlers: Schlock and Awe (TS-5186), Josh Bloch and Neal Gafter's 2009 JavaOne Technical Session presentation. Here's the concluding slide:
The Moral
- Strange and terrible methods lurk in libraries
- Some have innocuous sounding names
- If your code misbehaves
- Make sure you're calling the right methods
- Read the library documentation
- For API designers
- Don't violate the principle of least astonishment
- Don't violate the abstraction hierarchy
- Don't use similar names for wildly different behaviors
For completeness, there are also these methods that are analogous to Integer.getInteger
:
Boolean.getBoolean(String)
Long.getLong(String)
Related questions
- Most Astonishing Violation of the Principle of Least Astonishment
- Most awkward/misleading method in Java Base API ?
On autounboxing
The other issue, of course, is how the NullPointerException
gets thrown. To focus on this issue, we can simplify the snippet as follows:
Integer someInteger = null;
int num = someInteger; // throws NullPointerException!!!
Here's a quote from Effective Java 2nd Edition, Item 49: Prefer primitive types 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.
Related questions
- What is the difference between an int and an Integer in Java/C#?
- Why does autoboxing in Java allow me to have 3 possible values for a boolean?
- Is it guaranteed that new Integer(i) == i in Java? (YES!!!)
- When comparing two Integers in Java does auto-unboxing occur? (NO!!!)
- Java noob: generics over objects only? (yes, unfortunately)
Comparing an int and Integer in Java
For all the relational operators (including therefore <
and ==
), if one type is the boxed analogue of the other, then the boxed type is converted to the unboxed form.
So your code is equivalent to Foo.intValue() < foo;
. This is deeper than you might think: your Foo < foo
will throw a NullPointerException
if Foo
is null
.
Why can't I compare null field to a primitive
Because obj.n == 1
is interpreted as primitive integer comparison, so obj.n
will be auto-unboxed calling out.n.intValue()
, which leads to the exception.
Formally, JLS 15.21 makes it clear that compiler knows your code is a numeric comparison, and then JLS 15.21.1 applies which states:
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).
Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).
NullPointerException using Long after equality check
This is the problem:
value == -1 || value == null
Expressions are evaluated from left to right and since Long
must be unboxed first, JVM translates this to:
value.longValue() == -1 || value == null
And value.longValue()
throws NullPointerException
when value
is null
argument. It never reaches the second part of the expression.
It works when the order is different though:
value == null || value == -1
because if the value
is null
, the second part (that can cause NullPointerException
when value
is null
) is never executed due to boolean expression short-circuit evaluation.
Is this on spec or a bug in the JDK?
Of course this is not a bug. The way primitive value wrappers are unboxed is on spec (5.1.8. Unboxing Conversion):
- If
r
is a reference of typeLong
, then unboxing conversion convertsr
intor.longValue()
After unboxing is applied, the rest is standard Java.
Compare nullable Integer to 0
x
is a field in your class, so when you create it without making it to reference to any Integer
object (Integer x = new Integer(7)
for example), the compiler gives it a null
for you (the default values for Object references). It seems like you have hence: Integer x = null;
So to compare it just use the equals()
method that is implemented by Integer wrapper class.
new Integer(0).equals(x)
Related Topics
Attempt to Re-Open an Already-Closed Object: SQLitedatabase
Setnavigationitemselectedlistener Not Working
How to Exclude an Element from a Firestore Query
How to Create Thumbnail of Video Url Form Server
Changing Openssl Library in Android App for Httpclient
How to Send Array of Params Using Volley in Android
== and .Equals() Not Working in Java
Should I Strictly Avoid Using Enums on Android
How to Print to the Console in Android Studio
How to Update Information in an Android Activity from a Background Service
How to Encode String (Use Encrypt Messagedigest in Java) to Base64 String in Swift
How to Do a Cross Platform Encryption Method Working in Both iOS and Android (Aes Encryption Only..)
What Is the Equivalent of a Java Hashmap<String,Integer> in Swift
Simple Calculator with Jsp/Servlet and Ajax
How to Escape Apostrophe or Quotes on a Jsp (Used by JavaScript)