6

If you run the following code,

public class Foo{
    public static void main(String[] args){
        int id = new Bar().getId(); // throws unexpected NullPointerException
    }

    private static class Bar{
        private final Integer id;

        public Bar(){
            this(null);
        }

        public Bar(Integer id){
            this.id = id;
        }

        public Integer getId(){
            return id;
        }
    }
}

you will get the following stacktrace,

Exception in thread "main" java.lang.NullPointerException
    at Foo.main(Foo.java:3)

How come there's no compiler warning or anything? IMHO it's a pretty nasty subtlety with unboxing, or maybe I'm just naive.


Adding on to the answer provided by @Javier, if you're using Eclipse, you need to do the following to enable this:

  1. Navigate to Window > Preferences > Java > Compiler > Errors/Warnings
  2. Expand Potential programming problems
  3. Toggle Boxing and unboxing conversions to either "Warning", or "Error"
  4. Tap "OK"
Community
  • 1
  • 1
mre
  • 43,520
  • 33
  • 120
  • 170
  • I don't understand. Are you asking why the NPE happens or this is just a rant? What would be the specific answerable question? – madth3 Feb 20 '13 at 23:59

6 Answers6

6

I don't know what IDE are you using, but Eclipse has an option to enable warning on boxing and unboxing conversions. It is not possible to detect it as a null pointer access, since null is not immediatly unboxed, but via Bar.getId().

The expression of type Integer is unboxed into int
Foo.java line 3

Javier
  • 12,100
  • 5
  • 46
  • 57
  • I've been using Eclipse for ~3 years and I didn't know that! Sweet! – mre Feb 20 '13 at 23:51
  • 2
    It's annoying that eclipse can't turn on unboxing warnings without boxing! https://bugs.eclipse.org/bugs/show_bug.cgi?id=163065 – Kyle Sep 06 '13 at 03:24
6

If you try to use any method on a null or do anything that does not make sense with a null, it throws a NullPointerException.

Autounboxing is implemented with the [Integer object].intValue() method (or similar), so it throws a NullPointerException because you can't have null invoke a method.

Hope this helps!

ameed
  • 1,132
  • 6
  • 25
5

it appears that this behavior is documented in the JDK™ 5.0 Documentation,

..you can largely ignore the distinction between int and Integer, with a few caveats. An Integer expression can have a null value. If your program tries to autounbox null, it will throw a NullPointerException.

mre
  • 43,520
  • 33
  • 120
  • 170
0

NullPointerException is a RuntimeException than IDE can not detect when compile the code.

Instead, a good practice is check null before unboxing.

int getId(){
    if(id!=null){
        return id;
    }
    // return other or throw a checked exception.
}
lichengwu
  • 4,277
  • 6
  • 29
  • 42
0

Seems like a perfectly reasonable run time exception. If your main code was:

public static void main(String[] args){        
    Integer idObj = new Bar().getId();
    int id = idObj;   // throws NullPointerException
}

Nobody would be surprised about the null pointer exception. The Bar class returns a null, and a null object pointer can not be turned into a simple value. The implementation of the Bar class might be changed to initialize the id to a non-null value. This block of code can be compiled independently from the Bar class, and so assumptions about the dynamic workings of the Bar class should certainly not be coded into this block of code.

This is probably obvious, but the real solution is to use int for the id member, instead of Integer. This, then, has no issue:

private static class Bar{
    private final int id;

    public Bar(){
        this(0);
    }

    public Bar(int id){
        this.id = id;
    }

    public int getId(){
        return id;
    }
}

(But I suppose you already were aware of this :-) )

AgilePro
  • 5,588
  • 4
  • 33
  • 56
  • i did not say the exception was unreasonable, i said it was unexpected, especially since my IDE chose to ignore it by default. – mre Feb 21 '13 at 00:11
  • OK, I was trying to get around what is "expected" and "unexpected". It is a run-time exception, not something that can be necessarily determined from static analysis. How would you expect the IDE to behave in this situation? – AgilePro Feb 21 '13 at 00:19
  • I expected the IDE to at least warn me by default. Like I said, I think it's a pretty subtle runtime exception. – mre Feb 21 '13 at 00:21
  • You would expect it to determine all the situations where you might get a run time NPE? This strikes me as running up against Gödel's theorem. But I recommend avoiding the Integer class when you don't need it. – AgilePro Feb 21 '13 at 00:25
  • No, you're being hyperbolic. I would not expect it to account for all scenarios. But it looks like others were thinking the same since Eclipse provides such functionality when it comes to boxing/unboxing. – mre Feb 21 '13 at 00:27
  • 1
    Sorry about going hyperbolic, you are right. So the warning you want is simply that it is doing an inline type cast from an Integer to an int? I guess Eclipse can do that for you as a warning. – AgilePro Feb 21 '13 at 00:31
0

Boxing is nothing more than syntactical sugar for casting an object like Integer to the native equivalent 'int'. Natives can't be null but objects can. The boxing mechanism won't prevent NullPointerExceptions in these cases.

seand
  • 5,168
  • 1
  • 24
  • 37