具有自动装箱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时发生。