java: странное исключение NullPointerException в тернарном операторе (?:) - PullRequest
11 голосов
/ 09 марта 2011

Пожалуйста, примите во внимание этот фрагмент кода:

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), переменные testMin и verwachtMin должны быть эквивалентны.

Как и следовало ожидать, я лучше напишу последние 2 строки, чем первые 7. Однако, когда я передаю 3 нулевых значения этому методу, я получаю NPE для вычисления переменной verwachtMin.

Кто-нибудь знает, как это может произойти?Оценивает ли троичный оператор 2-ю часть, даже если условие не true?

(версия Java 1.6.0_21)

Ответы [ 5 ]

16 голосов
/ 09 марта 2011

Попробуйте:

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;

Типы альтернативных сторон троичного оператора были double и Double, что означает, что Double распаковывается до double, а затем при назначении мы имеем бокс от double до Double. Если значение min равно null, то распаковывающие NPE.

3 голосов
/ 09 марта 2011

Оценивает ли троичный оператор 2-ю часть, даже если условие не соответствует действительности

Нет - но он оценивает 3-ю часть, и я думаю, что в этом случае он пытается выполнить автоматическое подключение min (ведущий к NPE), потому что тип возвращаемого значения Math.max() является примитивным double и определяет тип возвращаемого значения для всего выражения.

Autoboxing / -unboxing от дьявола.

1 голос
/ 09 марта 2011

Проблема вызвана автобоксом *, а не троичным оператором.Вы используете Double тип оболочки, а не double примитивный тип.Поскольку Math.max() ожидает double параметров, а не Double с, происходит невидимый вызов Double#doubleValue(), прежде чем значения будут переданы Math.max().Однако вы не можете вызвать метод для объекта null - следовательно, NullPointerException.

Почему вы сначала используете Double вместо double?Переменная примитивного типа (например, double) просто не может быть null.


* Ну, в данном случае для автоматического подключения

0 голосов
/ 09 марта 2011

Math.max(min, avg - 3 * sd) здесь min, avg и sd автоматически переносятся с удвоения до двойного, что, когда один из них равен нулю, вызывает NPE.

0 голосов
/ 09 марта 2011

Автоматическая распаковка вызывает проблему. Подобный вопрос уже задавался ранее. Вы можете использовать double вместо Double, чтобы решить вашу проблему ..

...