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

标签 java conditional-operator language-specifications

这里有一点奇怪:

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

这将失败并显示 NullPointerException如果b1b2是假的。但这:

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

b1 时不会抛出 NPE是假的。

这是为什么?

最佳答案

正如您所想,第一种情况中的 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;
}

关于java - 使用时出现令人惊讶的 NullPointerException ? :,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48409983/

相关文章:

c++ - 在 while 循环中,最后一个逗号分隔的语句是否保证最后运行?

当我尝试通过包传递对象时出现 java.lang.IllegalArgumentException : Ilegal value,

java - 压缩的 ooP 是如何在 JVM 中实现的?

python - python中三元运算符的缩写

Cassandra 条件更新与 IF EXISTS 结合

java - 从 Object 转换为 boolean 有效的 Java 语言吗?

C# short/long/int 文字格式?

java - Tapestry 5 - 两个组件之间的通信

Java Play 框架 - NoClassDefFoundError : play/Configuration

java - 如何在 Java MongoDB 中查询整个单词