具有自动装箱function的三元运算符中的Java NPE?
今天早上我遇到了一个非常奇怪的NPE,并将其简化为一个简单的例子。 这是JVM错误还是正确的行为?
public class Test1 { class Item { Integer id = null; public Integer getId() {return id;} } public Integer f() { Item item = new Item(); // this works: //return item == null ? new Integer(1) : item.getId(); // NPE?? return item == null ? 1 : item.getId(); } public static void main(String[] args) { Test1 t = new Test1(); System.out.println("id is: " + String.valueOf(tf())); } }
编译和运行的输出:
$ javac Test1.java $ java Test1 Exception in thread "main" java.lang.NullPointerException at Test1.f(Test1.java:12) at Test1.main(Test1.java:16) $
表达式item == null ? 1 : item.getId()
的类型item == null ? 1 : item.getId()
item == null ? 1 : item.getId()
是int
而不是Integer
。 因此,Java需要将Integer
自动解包为int
(导致NullPointerException
)。 然后它自动将结果返回到一个Integer
(如果不是NullPointerException
, 它将从该方法返回)。
另一方面,表达式item == null ? new Integer(1) : item.getId()
item == null ? new Integer(1) : item.getId()
的类型为Integer
,不需要进行自动拆箱。
当您自动取消装入null
Integer
,会出现NullPointerException
(请参阅自动装箱 ),这就是您遇到的情况。
要回答您的问题,这是正确的行为。
如果您反编译类文件,您将清楚地看到您的NPE …
return Integer.valueOf(item != null ? item.getId().intValue() : 1);
item
可能不为null
,但是当你调用getId()
,返回null
。 当您尝试auto-unbox null
,您将获得一个NPE。
下面的返回类型是Integer
–
public Integer f() { Item item = new Item(); // this works: //return item == null ? new Integer(1) : item.getId(); // NPE?? return item == null ? 1 : item.getId(); }
以下结果 –
item == null ? 1 : item.getId()
在你的情况下为null
。
因此,JVM正在抛出NPE,因为它试图将autobox置为null
。
试试 –
new Integer(null); // and Integer.valueOf(null);
两者都会抛出NPE。
它发生是因为你使用条件运算符?
。 线
return item == null ? 1 : item.getId();
相当于
int result = item == null ? 1 : item.getId(); return result;
结果是int,因为表达式中的第一个操作数。 当您使用Integer显式换行1时,这就是您的代码工作的原因。 在这种情况下,编译器创建类似的东西
Integer result = item == null ? new Integer(1) : item.getId(); return result;
因此,NPE在尝试将item.getId()(即null)“强制转换”为int时发生。