为什么三元运算符给出空指针,而ifelse对应的不是?

时间:2014-09-19 07:48:27

标签: java nullpointerexception ternary-operator

我在下面的一个实例中得到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

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)

5 个答案:

答案 0 :(得分:9)

以下是the spec (§15.25.2)的相关引用:

  

布尔条件表达式是独立表达式(§15.2)。

     

布尔条件表达式的类型确定如下:

     
      
  • 如果第二个和第三个操作数都是Boolean类型,则条件表达式的类型为Boolean

  •   
  • 否则,条件表达式的类型为boolean

  •   

因此,整体表达式的类型被视为booleanBoolean值被自动装箱,导致NullPointerException


正如评论中所提到的,为什么以下不会引发异常?

return val == null ? null : "true".equalsIgnoreCase(val);

嗯,上面的规范摘录特别适用于指定为here (§15.25)布尔条件表达式

  

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

     

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

     
      
  • 表达式为booleanBoolean的独立表单(§15.2)。

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

  •   
  • Boolean的类实例创建表达式(§15.9)。

  •   
  • 方法调用表达式(§15.12),所选择的最具体方法(§15.12.2.5)的返回类型为booleanBoolean
      (注意,对于泛型方法,这是在实例化方法的类型参数之前的类型。)

  •   
  • 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)

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

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

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));
}