为什么三元运算给出了nullpointer,而ifelse对应的呢?
我在下面的一个实例中得到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); }
在线版
在线版本中main
反转 ,从withIfElse
输出null
,然后在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)
以下是规范(§15.25.2)中的相关引用:
布尔条件表达式是独立表达式(第15.2节 )。
布尔条件表达式的类型确定如下:
如果第二个和第三个操作数都是
Boolean
类型,则条件表达式的类型为Boolean
。否则,条件表达式的类型为
boolean
。
因此,整个表达式的类型被认为是boolean
,并且Boolean
值是自动装箱的,导致NullPointerException
。
正如评论中所提到的,为什么以下不会引发exception?
return val == null ? null : "true".equalsIgnoreCase(val);
那么,上面的规范摘录特别适用于布尔条件表达式, 这里指定(第15.25节) :
如果第二个和第三个操作数表达式都是布尔表达式 ,则条件表达式是布尔条件表达式。
为了对条件进行分类,以下表达式是布尔表达式:
具有
boolean
或Boolean
类型的独立表单(第15.2节 )的表达式。带括号的
boolean
表达式(第15.8.5节 )。类
Boolean
类实例创建表达式(第15.9节 )。方法调用表达式(第15.12节 ),所选择的最具体方法(第15.12.2.5节 )的返回类型为
boolean
或Boolean
。
(注意,对于generics方法,这是在实例化方法的类型参数之前的类型。)
boolean
条件表达式。
由于null
不是布尔表达式 ,因此整个条件表达式不是布尔条件表达式 。 参考表15.2(稍后在同一节中),我们可以看到这样的表达式被认为具有Boolean
类型,因此不会发生拆箱,也不会引发exception。
val == null ? defVal : "true".equalsIgnoreCase(val)
val == null ? defVal : "true".equalsIgnoreCase(val)
– 在这个表达式中,第三个参数是boolean
,并且由于三元运算符必须有一个静态类型,它将尝试取消null
,即NPE。 只有Boolean
的赋值才会再次引起装箱。 检查一下 。
因为自动装箱。 Java派生defVal
常见类型和"true".equalsIgnoreCase(val)
。 first的类型是布尔值,但是第二个布尔值。 由于未知原因,它认为普通类型将是布尔值(您可以在规范中找到规则)。
如果defVal
为null
则可以解释这一点。
使用三元表达式时,两个选项必须具有完全相同的类型,如果不是,则应用某些强制:
JLS 15.25“条件运算符?:”说:
如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是对T应用装箱转换(第5.1.7节)的结果,那么条件表达式的类型是T.
在这个表达式的情况下:
val == null ? defVal : "true".equalsIgnoreCase(val)
defVal
的Boolean
值是自动取消装箱的,以匹配字符串比较的boolean
结果。 尽管三元组的结果然后被自动装箱回Boolean
– 当决定如何投射时,三元组不会考虑外部任何东西。
好。 我们试着这样做吧
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)); }