5

Недавно я попытался выполнить следующие два фрагмента кода и был удивлен выходом.Как работает распаковка в коротких замыканиях булевых выражений?

Первое:

// ... 
System.out.println((Boolean)null || true); 
// ... 

Второе:

// ... 
System.out.println((Boolean)null || false); 
// ... 

Первый пример приводит следующий вывод:
истинные

Второй пример приводит следующий вывод:
Исключение в теме "main" jav a.lang.NullPointerException
      в com.blah.main (SanityCheck.java:26)

Я бы подумал, оба примера следует привести исключения нулевого указателя, так как применяется любое короткое замыкание лево- направо. Попытка уничтожить логическое значение из булева должна была провалиться перед другой стороной логического или была рассмотрена.

Может ли кто-нибудь объяснить это непоследовательное поведение?

+0

Это поведение выглядит несовместимым с [JLS] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24) «Во время выполнения слева -ограниченное выражение операнда сначала оценивается, если результат имеет тип Boolean, он подвергается распаковке преобразования « –

+2

SanityCheck.java – arynaq

ответ

2

Я возьму удар. Поскольку компилятор пытается интерпретировать два утверждения, основное отличие состоит в том, что утверждение с истинным с правой стороны не требуется для вычисления с левой буквой Boolean, тогда как утверждение с ложным справа.

Boolean - это объект, поэтому его можно установить в null. Это не исключение. Исключение NullPointerException выполняется при попытке выполнить операцию над булевым объектом, для которого установлено значение null. В истинном случае компилятор передаст значение null в значение Boolean и потому, что OR'ing с true всегда будет давать true, условие is true. В ложном случае компилятор снова передает значение null в Boolean, после чего он проверяет значение false, и если условие является ложным, ему необходимо вычислить OR с помощью логического значения, поскольку в конечном итоге это условие может быть истинным или ложным. Когда вычисление происходит, генерируется исключение NullPointerException.

+0

Это хороший ответ, но я думал, что любое короткое замыкание произошло слева направо. Если левый операнд имеет значение true в a или, правый операнд не оценивается. Аналогично, если левый операнд имеет значение true в a и, правый операнд не оценивается.Я предполагаю, что это может быть какая-то оптимизация компилятором, поэтому я попытаюсь декомпилировать файл класса. – studro

+0

На самом деле я думаю, что неправильно понял, что вы написали, - короткое замыкание даже не применяется, потому что оно оптимизировано во время компиляции. Пятно на. – studro

+0

Правильно! Кастинг проходит, и истинные проходы. Тогда нет необходимости в истинном OR *, потому что оно всегда будет истинным. – user1549672

4

Я запустил файл класса через JAD, чтобы посмотреть, как выглядел оптимизированный код. Для истинного случая:

// ... 
System.out.println(true); 
// ... 

Для ложного случая:

// ... 
System.out.println(null.booleanValue()); 
// ... 
1

Я не могу воспроизвести результаты. Фактически я получаю NPE для обоих случаев.

В соответствии с JLS выражение левой части операнда всегда оценивается первым. Когда оценивается (Boolean)null, автоматическое разблокирование выполняется на нулевом булевом объекте. В частности, основной код null.booleanValue() вызывает NPE.

+1

Вы не должны получать NPE для истинного случая. (Boolean) null запускается просто отлично. Даже если он сначала оценивается, он не должен вызывать исключение NullPointerException. – user1549672

+0

@ user1549672 Это действительно происходит со мной, поэтому я все еще пытаюсь выяснить проблему. Влияет ли результат на версию JDK, которую я использую? –

+0

Я не уверен. В какой версии вы работаете? – user1549672