views:

182

answers:

2

Eventually I got the answer, but it puzzled me for a while.

Why does the following code throws NullPointerException when run?

import java.util.*;

class WhyNullPointerException {
    public static void main( String [] args ){
       // Create a map
        Map<String,Integer> m = new HashMap<String,Integer>();
        // Get the previous value, obviously null.
        Integer a = m.get( "oscar" );
        // If a is null put 1, else increase a
        int p = a == null ? 
            m.put( "oscar", 1) : 
            m.put( "oscar", a++ ); // Stacktrace reports Npe in this line
    }
}
+10  A: 

Because m.put returns null (which indicates that there's no "previous" value) while you're trying to assign it to int. Replace int p by Integer p and it will work.

This is specified in JLS 5.1.8:

5.1.8 Unboxing Conversion

At run time, unboxing conversion proceeds as follows:

  • If r is null, unboxing conversion throws a NullPointerException

Unrelated to the problem, just a side suggestion with DRY in mind, consider writing it so:

    Integer p = m.put("oscar", a == null ? 1 : a++);

It's a bit more readable :)

BalusC
Does this have something to do with auto boxing?
Johannes Schaub - litb
@Johannes: Indeed it does. The Integer is auto-unboxed into an int - if the Integer happens to be null, the unboxing throws.
Anon.
@Johannes: Indeed, `null` cannot be unboxed to a primitive, it will throw NPE. See also [Autoboxing guide](http://java.sun.com/j2se/1.5.0/docs/guide/language/autoboxing.html).
BalusC
A `null` `Integer` won't unbox into an `int` :)
Dolph
Actually the stacktrace is missleading, because it makes you think the problem is in `a++` but try substituting with any number , ie `put( "oscar", /*a++*/ 4`) for instance, and the line returned by the Npe would be where `put("oscar",1)` instead. I'm not sure why does it report it in that line.
OscarRyz
+4  A: 

You are assigning int p to the return value of m.put(). But put() returns null in this situation, and you can't assign an int to null.

From the Javadocs for HashMap.put():

Returns: previous value associated with specified key, or null if there was no mapping for key.

Justin Ardini
+1 correct! 3,2,1,0
OscarRyz