问题
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:
- Navigate to Window > Preferences > Java > Compiler > Errors/Warnings
- Expand Potential programming problems
- Toggle Boxing and unboxing conversions to either "Warning", or "Error"
- Tap "OK"
回答1:
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
回答2:
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!
回答3:
it appears that this behavior is documented in the JDK™ 5.0 Documentation,
..you can largely ignore the distinction between
int
andInteger
, with a few caveats. AnInteger
expression can have a null value. If your program tries to autounbox null, it will throw aNullPointerException
.
回答4:
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.
}
回答5:
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 :-) )
回答6:
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.
来源:https://stackoverflow.com/questions/14992077/unboxing-a-null-boxed-object-throws-unexpected-nullpointerexception