具有自动装箱功能的三元运算符中的Java NPE?

时间:2011-10-18 17:57:25

标签: java nullpointerexception

今天早上我遇到了一个非常奇怪的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(t.f()));
    }   
}

编译和运行的输出:

$ javac Test1.java 
$ java Test1
Exception in thread "main" java.lang.NullPointerException
at Test1.f(Test1.java:12)
at Test1.main(Test1.java:16)
$

5 个答案:

答案 0 :(得分:31)

表达式item == null ? 1 : item.getId()的类型为int而非Integer。因此,Java需要将Integer自动取消装箱到int(导致NullPointerException)。然后它会自动将结果返回到Integer(如果不是NullPointerException那么)从方法返回。

另一方面,表达式item == null ? new Integer(1) : item.getId()的类型为Integer,无需自动取消装箱。

当您自动取消装箱null Integer时,您会收到NullPointerException(请参阅Autoboxing),这就是您所遇到的问题。

要回答您的问题,这是正确的行为。

答案 1 :(得分:3)

item可能不是null,但是当您致电getId()时,就会返回null。当您尝试自动取消装箱null时,您会获得一个NPE。

答案 2 :(得分:3)

如果您反编译该类文件,您将清楚地看到您的NPE ......

return Integer.valueOf(item != null ? item.getId().intValue() : 1);

答案 3 :(得分:2)

以下返回类型为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,因为它正在尝试自动装箱null

尝试 -

new Integer(null); // and
Integer.valueOf(null);

两者都会抛出NPE。

答案 4 :(得分:2)

之所以发生这种情况,是因为您使用的是条件运算符?。线

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时发生。