Почему это бросает NullPointerException
public static void main(String[] args) throws Exception {
Boolean b = true ? returnsNull() : false; // NPE on this line.
System.out.println(b);
}
public static Boolean returnsNull() {
return null;
}
пока это не
public static void main(String[] args) throws Exception {
Boolean b = true ? null : false;
System.out.println(b); // null
}
?
Кстати, решение заключается в замене false
на, Boolean.FALSE
чтобы избежать null
распаковки в boolean
- что невозможно. Но вопрос не в этом. Вопрос в том, почему ? Есть ли ссылки в JLS, которые подтверждают такое поведение, особенно во втором случае?
Ответы:
Разница в том, что явный тип
returnsNull()
метода влияет на статическую типизацию выражений во время компиляции:См. Спецификацию языка Java, раздел 15.25. Условный оператор? :
Для E1 типами 2-го и 3-го операндов являются
Boolean
иboolean
соответственно, поэтому применяется это предложение:Поскольку тип выражения - это
boolean
, второй операнд должен быть приведен кboolean
. Компилятор вставляет код автоматической распаковки во второй операнд (возвращаемое значениеreturnsNull()
), чтобы он стал типомboolean
. Это, конечно, вызывает NPE изnull
возвращаемого во время выполнения.Для E2 типы 2-го и 3-го операндов
<special null type>
(неBoolean
как в E1!) Иboolean
соответственно, поэтому не применяется конкретное предложение о типизации ( прочтите их! ), Поэтому применяется последнее предложение «иначе»:<special null type>
(см. §4.1 )boolean
<special null type>
(см. Последний пункт в списке преобразований боксов в §5.1.7 )Boolean
Таким образом, условное выражение имеет тип,
Boolean
и третий операнд должен быть приведен в соответствиеBoolean
. Компилятор вставляет код автоматической упаковки для третьего операнда (false
). Для второго операнда не требуется автоматическая распаковка, как вE1
, поэтому автоматическая распаковка NPE при возврате не требуетсяnull
.Этот вопрос требует аналогичного анализа:
Условный оператор Java?: Тип результата
источник
lub
вlub(T1,T2)
стенд для?Линия:
внутренне преобразуется в:
выполнить распаковку; таким образом:
null.booleanValue()
даст NPEЭто одна из основных ошибок при использовании автобокса. Это поведение действительно задокументировано в 5.1.8 JLS.
Изменить: я считаю, что распаковка связана с тем, что третий оператор имеет логический тип, например (добавлено неявное приведение):
источник
Из Спецификации языка Java, раздел 15.25 :
Итак, первый пример пытается вызвать
Boolean.booleanValue()
для того , чтобы преобразоватьBoolean
вboolean
в соответствии с первым правилом.Во втором случае первый операнд имеет нулевой тип, а второй не является ссылочным типом, поэтому применяется преобразование автобокса:
источник
null
.boolean
это не ссылочный тип.Мы можем увидеть эту проблему из байтового кода. В строке 3 основного байтового кода,
3: invokevirtual #3 // Method java/lang/Boolean.booleanValue:()Z
боксирующего логического значения null,invokevirtual
методаjava.lang.Boolean.booleanValue
, он, конечно же, выбрасывает NPE.источник