Java的简写If语句在返回对象中存在空值时会导致NullPointerException异常。

7
为什么这段代码会返回错误:java.lang.NullPointerException。
Object obj = null;
Long lNull = null;
Long res = obj == null ? lNull : 10L;

但是以下这种方法没有任何错误:
Object obj = null;
Long res = obj == null ? null : 10L;

4
之前有人问过类似的问题,但找不到重复的链接。原文如下:“如果第二个和第三个操作数中有一个是基本类型T,而另一个的类型是将T应用于装箱转换(§5.1.7)的结果,则条件表达式的类型为T。” - luk2302
https://dev59.com/02Mm5IYBdhLWcg3whfSe - Sotirios Delimanolis
https://stackoverflow.com/questions/27730895/strange-nullpointerexception-in-ternary-conditional-expression - Sotirios Delimanolis
https://dev59.com/SHA75IYBdhLWcg3wfpKr - Sotirios Delimanolis
https://stackoverflow.com/questions/31612888/nullpointerexception-and-unboxing - Sotirios Delimanolis
3个回答

5
在第二种情况下,编译器可以推断出null必须是Long类型。而在第一种情况下,编译器不会做出这样的推断,而是认为表达式返回一个long类型。你可以像这样看到这种情况(即修复它),
Long res = obj == null ? lNull : (Long) 10L;

不会引发NullPointerException异常。

4
错误是因为在您的情况下,标准要求取消包装箱类型的值:
如果第二个和第三个操作数中的一个是基本类型T,并且另一个的类型是应用于T的装箱转换(§5.1.7),则条件表达式的类型为T。
在您的情况下,T是long,因为10L是long而lNull是Long,即将长转换应用于的结果。
标准进一步说明:
如有必要,则对结果执行取消装箱转换。
这就是引发异常的原因。 请注意,如果反转条件,则不再抛出异常:
Long res = obj != null ? lNull : 10L;

您可以通过明确要求 Long 而不是使用 long 来解决问题,即:
Long res = obj == null ? lNull : Long.valueOf(10L);

2

JLS第15.25节讨论了对于第二个和第三个操作数类型的各种组合,条件运算符表达式的类型。有很多表格将两种类型在所有相关组合中映射到结果类型。

3rd → long
2nd ↓  
...
Long  long
...
null  lub(null,Long)
您的第一个示例包含一个 Long 和一个 long,结果为 long。这需要对 lNull 进行拆箱操作,这解释了为什么会出现 NullPointerException
您的第二个示例包含一个 null 字面量(不是一个 null 变量)和一个 long。这将得到 "lub(null,Long)" 或者 Long,并且不会执行拆箱操作,因此不会观察到 NPE。
您可以通过使用第一个示例或将 10L 强制转换为 Long 来避免 NPE,因为 nullLong 会产生一个 Long
3rd → Long
2nd ↓  
...
Long  Long

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接