java: weird NullPointerException in ternary operat

2020-02-26 06:48发布

问题:

Please consider this code snippet:

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

As far as I know (and for what my IDE can tell me), the variables testMin and verwachtMin should be equivalent.

As you might expect, I'd rather write the last 2 lines than the first 7. However, when I pass 3 null values to this method, I get an NPE on the calculation of the verwachtMin variable.

Does anyone know how this can happen? Does the ternary operator evaluate the 2nd part, even when the condition is not true?

(Java version 1.6.0_21)

回答1:

Try:

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

or

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

The types of the alternate sides of the ternary operator were double and Double, which means that the Double gets unboxed to double, and then on assignment we have a boxing from double to Double. If the value of min is null then the unboxing NPEs.



回答2:

Does the ternary operator evaluate the 2nd part, even when the condition is not true

No - but it evaluates the 3rd part and I think in this case it tries to autounbox min (leading to the NPE) because the return type of Math.max() is primitive double and determines the return type of the entire expression.

Autoboxing/-unboxing is of the devil.



回答3:

The problem is caused by autoboxing*, not by the ternary operator. You are using the Double wrapper type rather than the double primitive type. Because Math.max() expects double parameters, not Doubles, there is an invisible call to Double#doubleValue() before the values are passed to Math.max(). However, you can't call a method on a null object - hence the NullPointerException.

Why are you using Double instead of double in the first place? A primitive-type variable (such as a double) simply cannot be null.


*Well, autounboxing, in this case



回答4:

Auto-unboxing causes the problem. Similar question has been asked before .. You sould use double instead of Double to solve your problem..



回答5:

Math.max(min, avg - 3 * sd) here min, avg and sd are autounboxed from Double to double which when one of them is null causes an NPE.