Подтвердить что ты не робот

NullPointerException через авто-бокс-поведение троянного оператора Java

На днях я столкнулся с действительно странным NullPointerException, вызванным неожиданным типом в тернарном операторе. Учитывая эту (бесполезную примерную) функцию:

Integer getNumber() {
    return null;
}

Я ожидал, что следующие два сегмента кода будут точно идентичными после компиляции:

Integer number;
if (condition) {
    number = getNumber();
} else {
    number = 0;
}

против.

Integer number = (condition) ? getNumber() : 0;

.

Выключается, если condition - true, условие if работает отлично, а троичный отступ во втором сегменте кода вызывает NullPointerException. Кажется, что тройная операция решила набрать оба варианта до int, прежде чем автоматически поместить результат в Integer!?! Фактически, если я явно применяю 0 к Integer, исключение исчезает. Другими словами:

Integer number = (condition) ? getNumber() : 0;

- это не то же самое, что:

Integer number = (condition) ? getNumber() : (Integer) 0;

.

Итак, кажется, что существует байт-кодовое различие между тернарным оператором и эквивалентным if-else -statement (чего я не ожидал). Что вызывает три вопроса: почему существует разница? Является ли это ошибкой в ​​тройной реализации или есть причина для типа cast? Учитывая, что существует разница, тройная операция более или менее эффективна, чем эквивалентное if -стояние (я знаю, разница не может быть огромной, но все же)?

4b9b3361

Ответ 1

Согласно JLS: -

Тип условного выражения определяется следующим образом:

  • Если второй и третий операнды имеют один и тот же тип (который может быть нулевым типом), то это тип условного выражение.
  • Если один из второго и третьего операндов имеет примитивный тип T, а тип другого - результат применения преобразования бокса (П. 5.1.7) в T, то тип условного выражения равен T.

Ответ 2

Проблема в том, что:

Integer number = (condition) ? getNumber() : 0;

Принудительно распаковывает и переустанавливает результат getNumber(). Это связано с тем, что ложная часть тройки (0) является целым числом, поэтому она пытается преобразовать результат getNumber() в int. Принимая во внимание следующее:

Integer number = (condition) ? getNumber() : (Integer) 0;

Это не ошибка, а именно то, как Java решила что-то сделать.

Ответ 3

Вот как он должен работать. Тернарный оператор не должен быть эквивалентен регулярному выражению if. Телами if и else являются операторы, а части, следующие за ? и :, являются выражениями, которые должны оцениваться одним и тем же типом.

Другими словами: a = b ? c : d не должен быть эквивалентен if (b) a = c; else a = d;. Вместо этого b ? c : d является выражением само по себе, а присвоение его результата a не повлияет на результат.