我在下面的一个实例中得到NullPointerException,而它的对应物运行顺畅。
public static void main(String[] args){
System.out.println(withTernary(null, null)); //Null Pointer
System.out.println(withIfElse(null, null)); //No Exception
}
private static Boolean withTernary(String val, Boolean defVal){
return val == null ? defVal : "true".equalsIgnoreCase(val);
}
private static Boolean withIfElse(String val, Boolean defVal){
if (val == null) return defVal;
else return "true".equalsIgnoreCase(val);
}
Online version with the lines in main
reversed,从null
输出withIfElse
,然后在withTernary
中失败。
我正在使用以下java版本
java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-462-11M4609)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-462, mixed mode)
答案 0 :(得分:9)
以下是the spec (§15.25.2)的相关引用:
布尔条件表达式是独立表达式(§15.2)。
布尔条件表达式的类型确定如下:
如果第二个和第三个操作数都是
Boolean
类型,则条件表达式的类型为Boolean
。否则,条件表达式的类型为
boolean
。
因此,整体表达式的类型被视为boolean
,Boolean
值被自动装箱,导致NullPointerException
。
正如评论中所提到的,为什么以下不会引发异常?
return val == null ? null : "true".equalsIgnoreCase(val);
嗯,上面的规范摘录特别适用于指定为here (§15.25)的布尔条件表达式:
如果第二个和第三个操作数表达式都是布尔表达式,则条件表达式是一个布尔条件表达式。
为了对条件进行分类,以下表达式是布尔表达式:
表达式为
boolean
或Boolean
的独立表单(§15.2)。带括号的
boolean
表达式(§15.8.5)。类
Boolean
的类实例创建表达式(§15.9)。方法调用表达式(§15.12),所选择的最具体方法(§15.12.2.5)的返回类型为
boolean
或Boolean
。
(注意,对于泛型方法,这是在实例化方法的类型参数之前的类型。)
boolean
条件表达式。
由于null
不是布尔表达式,因此整个条件表达式不是布尔条件表达式。参考表15.2(稍后在同一节中),我们可以看到这样的表达式被认为具有Boolean
类型,因此不会发生拆箱,也不会引发异常。
答案 1 :(得分:7)
val == null ? defVal : "true".equalsIgnoreCase(val)
- 在这个表达式中,第三个参数是boolean
,由于三元运算符必须有一个静态类型,它将尝试将null
取消装箱,因此NPE。只有Boolean
的分配才会再次导致拳击。
检查this。
答案 2 :(得分:4)
因为自动装箱。 Java派生defVal
和"true".equalsIgnoreCase(val)
的通用类型。 first的类型是布尔值,但是第二个布尔值。由于未知原因,它认为普通类型将是布尔值(您可以在规范中找到规则)。
答案 3 :(得分:3)
如果defVal
为null
,则可以解释这一点。
使用三元表达式,两个选项必须具有完全相同的类型,如果不是,则应用某些强制:
JLS 15.25 "Conditional operator ? :"说:
如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是将装箱转换(第5.1.7节)应用于T的结果,则条件表达式的类型为T. / p>
对于这个表达式:
val == null ? defVal : "true".equalsIgnoreCase(val)
Boolean
的{{1}}值会自动取消装箱,以匹配字符串比较的defVal
结果。尽管事实上三元的结果然后被自动装箱回到boolean
- 当决定如何投射时,三元组不会考虑任何其他东西。
答案 4 :(得分:2)
确定。我们试试这个方式
public static void main(String[] args){
System.out.println(withTernary(null, null));
}
private static Boolean withTernary(String val, Boolean defVal){
return (val == null ? defVal : Boolean.valueOf("true".equalsIgnoreCase(val)));
}
现在它会正常工作。现在这里没有unboxing
,也不会给你例外。
但另一方面,由于null
unbox
,您将获得NPE
public static void main(String[] args){
System.out.println(withTernary(null, null)); //Null Pointer
}
private static Boolean withTernary(String val, Boolean defVal){
return (val == null ? defVal : "true".equalsIgnoreCase(val));
}