During one of the Java classes I teach, a student came up to me with a peculiar bug. Below is a simplified version:
HashMap<String,Boolean> map = new HashMap<String,Boolean>(); if (map.get("a") == true) // -> NullPointerException // do something
The NullPointerException here seems odd. While the
== true seemed
superfluous, I initially thought this would work. Even if it didn't, I couldn't
understand why this would give a NullPointerException.
A NullPointerException occurs when you try to use a reference that hasn't been
initialized yet (its value is null), but the only reference used here is
was definitely initialized!
I tried a few things:
System.out.println( map.get("a") ); // -> null
As I expected, this gave a
Then I tried:
System.out.println( null == true ); // -> CompileError: Incomparable types: <null> and boolean
Ok, so I had forgotten that in Java, you can't compare two objects of different types.
In some other languages,
null is considered "falsy".
But when I try:
System.out.println( map.get("a") == true ) // -> NullPointerException
Where is the
NullPointerException coming from?
Introduced in Java 1.5 (later called Java 5), autoboxing and unboxing is the automatic conversion of primitives and their wrapper classes.
Before Java 1.5, you had to manually convert the wrapper class to its primitive form by calling a specific function.
For example, if you created an ArrayList of Integers, you would need to call
intValue() function on the Integer object to get the primitive value
int x = arr.get(0); // Wrong, will give you an error int x = arr.get(0).intValue(); // Correct!
With autoboxing/unboxing, Java will implicitly call these functions (such as
intValue) from the wrapper classes when it notices you are trying to use
the primitive value.
map.get(x) will return a Boolean object, but will also return
x is not found in the HashMap. Note that null is a valid value for a Boolean
object (or any Java object)
However, Java sees that I'm comparing a Boolean object with a boolean
primitive, so it implicitly calls the Boolean object's
map.get(x) returns null, Java is actually implicitly calling
booleanValue() on the null object, hence the
The solution is to check if the object is
null before performing a comparison
if( map.get("a") != null && map.get("a") == true ) // do something
or, more simply,
if( map.get("a") != null && map.get("a") ) // do something