java:三元运算符中的怪异NullPointerException(?:)

时间:2011-03-09 13:55:30

标签: java nullpointerexception ternary-operator

请考虑以下代码段:

private static void doSomething(Double avg, Double min, Double sd) {
    final Double testMin;
    if (avg != null) {
        testMin = Math.max(min, avg - 3 * sd);
    } else {
        testMin = min;
    }
    System.out.println("testMin=" + testMin);

    final Double verwachtMin = avg != null ? Math.max(min, avg - 3 * sd) : min;
    System.out.println("verwachtMin=" + verwachtMin);
}

据我所知(以及我的IDE可以告诉我的内容),变量testMinverwachtMin应该是等效的。

正如您所料,我宁愿写下最后两行而不是第一行。但是,当我将3个空值传递给此方法时,我会计算verwachtMin变量的NPE。

有谁知道这会怎么样?三元运算符是否评估第二部分,即使条件不是true

(Java版本1.6.0_21)

5 个答案:

答案 0 :(得分:15)

尝试:

final Double verwachtMin = avg != null ? new Double(Math.max(min, avg - 3 * sd)) : min;

final Double verwachtMin = avg != null ? Double.valueOf(Math.max(min, avg - 3 * sd)) : min;

三元运算符的备用边的类型是doubleDouble,这意味着Double被取消装箱到double,然后在分配时我们有从doubleDouble的拳击。如果min的值为null,则取消装箱NPE。

答案 1 :(得分:3)

  

三元运算符是否评估第二部分,即使条件也是如此   不是真的

否 - 但它会评估第3部分,我认为在这种情况下它会尝试自动加载min(导致NPE),因为Math.max()的返回类型是原始的double和确定整个表达式的返回类型。

Autoboxing / -unboxing是魔鬼。

答案 2 :(得分:1)

问题是由autoboxing *引起的,而不是由三元运算符引起的。您正在使用Double包装器类型而不是double基元类型。由于Math.max()需要double参数,而不是Double s,因此在将值传递给Math.max()之前,会对Double#doubleValue()进行不可见的调用。但是,您无法在null对象上调用方法 - 因此NullPointerException

为什么您首先使用Double而不是double?原始类型变量(例如double)根本不能是null


*嗯,autounboxing,在这种情况下

答案 3 :(得分:0)

自动取消装箱会导致问题。之前已经问过类似的问题..你应该使用double而不是Double来解决你的问题..

答案 4 :(得分:0)

Math.max(min, avg - 3 * sd)此处minavgsd自动从Double到double,当其中一个为null时会导致NPE。