Dav*_*ser 26 java ternary-operator nullpointerexception
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;
}
}
Run Code Online (Sandbox Code Playgroud)
在第四次打电话给method()我时,我NullPointerException在指示的线上投掷method().如果我重构那条线
Long v = (map == null) ? thing.value : map.get(thing);
Run Code Online (Sandbox Code Playgroud)
至
Long v;
if (map == null) {
v = thing.value;
} else {
v = map.get(thing);
}
Run Code Online (Sandbox Code Playgroud)
我没有NullPointerException,方法的行为应该如此.问题是:为什么?
在我看来,编译器期望?运算符的结果long是自动取消装箱(降级Long到long)调用的结果map.get(thing)(可能返回null并因此抛出a NullPointerException).恕我直言应该期待的结果,?运营商要Long和自动装箱(推广long到Long)thing.value代替.
更好的是,如果我重构这个陈述:
Long v = (map == null) ? thing.value : map.get(thing);
Run Code Online (Sandbox Code Playgroud)
这个(铸造long到Long明确):
Long v = (map == null) ? (Long)thing.value : map.get(thing);
Run Code Online (Sandbox Code Playgroud)
我的IDE(IntelliJ)说,转换是多余的,但编译的代码按预期工作,并没有抛出NullPointerException!:-D
Roh*_*ain 29
考虑你的条件表达式:
(map == null) ? thing.value : map.get(thing)
Run Code Online (Sandbox Code Playgroud)
该表达式的结果将是long,因为类型thing.value是long.参见JLS§15.25 - 条件运算符.JLS 8中的表格是一个很好的补充.它阐明了不同输入类型的所有可能输出类型.与条件表达式类型相关的混淆程度如此之多.
现在,当您调用此方法时:
method(thing);
Run Code Online (Sandbox Code Playgroud)
该map不是null,这样的条件map == null在表达式求false,然后计算map.get(thing)得到的结果.
由于map尚未进入,map.get(thing)将返回null.但是由于结果的类型是long,执行了拆箱操作null,这导致了NPE.
现在,当你明确地投thing.value给Long,表达的类型变得Long.因此,不会对结果执行拆箱map.get(thing),并将null其分配给Long v.
| 归档时间: |
|
| 查看次数: |
1326 次 |
| 最近记录: |