public class Npe {
static class Thing {
long value;
}
public static Map<Thing, Long> map;
public static void main(String[] args) {
Thing thing = new Thing();
method(null); // returns -1
method(thing); // returns 0
map = new HashMap<Thing, Long>();
method(null); // returns -1
method(thing); // NullPointerException thrown inside this method call
}
public static long method(Thing thing) {
if (thing == null) {
return -1;
}
Long v = (map == null) ? thing.value : map.get(thing); // NPE here
if (v == null) {
v = thing.value;
}
return v;
}
}
第四次调用method()
时,在method()
内部指定行抛出NullPointerException
。如果我将该行重构为
Long v = (map == null) ? thing.value : map.get(thing);
toLong v;
if (map == null) {
v = thing.value;
} else {
v = map.get(thing);
}
我没有收到NullPointerException
异常,方法的行为也符合预期。问题是:为什么呢?
在我看来,编译器期望?
操作符的结果是long
,因此它会自动取消装箱(从Long
降级为long
)对map.get(thing)
的调用结果(这可能返回null
,从而抛出NullPointerException
)。我认为它应该期望?
操作符的结果是Long
,并将thing.value
自动装箱(将long
提升为Long
)。
更好的做法是,如果我重构这个语句:
Long v = (map == null) ? thing.value : map.get(thing);
将long
显式转换为Long
:
Long v = (map == null) ? (Long)thing.value : map.get(thing);
我的IDE(IntelliJ)提示这个强制类型转换是多余的,但编译后代码按预期工作且不会抛出NullPointerException
异常! :-D