为什么三元运算给出了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节) :

如果第二个和第三个操作数表达式都是布尔表达式 ,则条件表达式是布尔条件表达式。

为了对条件进行分类,以下表达式是布尔表达式:

  • 具有booleanBoolean类型的独立表单(第15.2节 )的表达式。

  • 带括号的boolean表达式(第15.8.5节 )。

  • Boolean类实例创建表达式(第15.9节 )。

  • 方法调用表达式(第15.12节 ),所选择的最具体方法(第15.12.2.5节 )的返回类型为booleanBoolean
    (注意,对于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的类型是布尔值,但是第二个布尔值。 由于未知原因,它认为普通类型将是布尔值(您可以在规范中找到规则)。

如果defValnull则可以解释这一点。

使用三元表达式时,两个选项必须具有完全相同的类型,如果不是,则应用某些强制:

JLS 15.25“条件运算符?:”说:

如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是对T应用装箱转换(第5.1.7节)的结果,那么条件表达式的类型是T.

在这个表达式的情况下:

 val == null ? defVal : "true".equalsIgnoreCase(val) 

defValBoolean值是自动取消装箱的,以匹配字符串比较的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)); }