使用?时出现令人惊讶的NullPointerException:

时间:2018-01-23 20:07:52

标签: java conditional-operator language-specifications

这有点古怪:

Integer oddity(boolean b1, boolean b2) {
  return b1 ? 0 : b2 ? 1 : null;
}

如果NullPointerExceptionb1为假,则b2会失败。但是这个:

Integer oddity(boolean b1) {
  return b1 ? 0 : null;
}

b1为假时,不会抛出NPE。

为什么会这样?

1 个答案:

答案 0 :(得分:2)

正如您可能想象的那样,第一种情况下的NullPointerException是隐式拆箱的结果。这就像所描述的那样in JLS Sec 15.25;但规则很复杂,并且有一些棘手的方面。

这里令人惊讶的是:

System.out.println(b ? 0 : null);

不一样
Integer v = null;
System.out.println(b ? 0 : v);
  • 第一种情况中的条件表达式具有Integer类型:0被加框为Integer.valueOf(0)。因此,此语句将正常完成,打印0null
  • 第二种情况中的条件表达式具有int类型:v 未装箱v.intValue()。因此,此声明将打印0,或者使用NullPointerException失败。

所以:问题中的第一个例子实际上是这两种情况的组合。插入隐式装箱和拆箱,它变为:

return Integer.valueOf(b1 ? 0 : (b2 ? Integer.valueOf(1) : null).intValue());

可能会因调用intValue()而失败;而问题中的第二个例子是:

return b1 ? Integer.valueOf(0) : null;

这不会失败。

如果你想返回0,1或null,最小的改变是明确地0包装:

return b1 ? Integer.valueOf(0) : b2 ? 1 : null;

这看起来很尴尬,因为0和1的表示方式不同。你也可以明确地装箱1:

return b1 ? Integer.valueOf(0) : b2 ? Integer.valueOf(1) : null;

哪个有效,但是很冗长,而且一些善意的同事(或者你,几个月后回到它,忘记了明确拳击的原因)将取消拳击,因为你不需要那个,对吧?

就个人而言 - 最近花了很多时间仔细研究条件运算符 - 我会选择完全避免它,并且不会冒犯其好奇的类型规则的风险。

if (b1) {
  return 0;
} else if (b2) {
  return 1;
} else {
  return null;
}