Проверьте, имеет ли значение null Boolean значение true, приводит к исключению

169

У меня есть следующий код:

Boolean bool = null;

try 
{
    if (bool)
    {
        //DoSomething
    }                   
} 
catch (Exception e) 
{
    System.out.println(e.getMessage());             
}

Почему моя проверка на булеву переменную "bool" приводит к исключению? Разве он не должен просто перепрыгнуть через оператор if, когда «видит», что это неправда? Когда я удаляю оператор if или проверяю, не является ли он нулевым, исключение исчезает.

орнитолог
источник
3
Ответы выше о распаковке объектов верны. Для полноты картины, однако, вы также можете изменить свой код, чтобы использовать примитив «логический» вместо обёртки объекта «Логический». Вам также следует освежить в себе разницу между примитивом и объектом.
Марво
Между тем ... if (bool == Boolean.TRUE)оценивает false без генерации исключения. Не уверен, было ли это намеренно в случае, который я только что нашел.
simon.watts
2
@ simon.watts, который был бы ложным для boolтого, чтобы быть nullИЛИ, если Booleanбыл построен явно (а не как ссылка Boolean.TRUE). Так что не рекомендуется; в отличие от того, if (Boolean.TRUE.equals(bool))который будет работать, как ожидалось, в том числе безопасно обрабатывать nullстоимость.
StaxMan

Ответы:

171

Когда у вас есть, booleanэто может быть trueили false. Тем не менее, когда у вас есть, Booleanэто может быть либо Boolean.TRUE, Boolean.FALSEлибо nullкак любой другой объект.

В вашем конкретном случае, оператор Booleanis nullи is ifзапускает неявное преобразование в booleanто, что производит NullPointerException. Вам может понадобиться вместо этого:

if(bool != null && bool) { ... }
K-Балло
источник
23
Технически, это Booleanможет быть любое количество истинных примеров, а не просто Boolean.TRUE. Например new Boolean(true).
Стив Куо
1
Я изо всех сил пытаюсь понять, почему if (myBoolean)(где myBooleanэто Boolean) не вызывает ошибку компилятора или, по крайней мере, предупреждение. Это гоча точно.
Джош М.
1
@JoshM. Это происходит потому , что Java делает бокс и распаковка оберток: docs.oracle.com/javase/tutorial/java/data/autoboxing.html
Vinicius
3
@Vinicius уверен, но в этом случае компилятор должен либо сделать для нас нулевое значение, по крайней мере, через предупреждение компилятора.
Джош М.
2
@JoshM. Больше не могу согласиться :)
Виниций
402

Если вам не нравятся дополнительные нулевые проверки:

if (Boolean.TRUE.equals(value)) {...}
AvrDragon
источник
1
@AvrDragon: равно ли требуется? Оператор == работает здесь, так как логическое значение имеет только два значения
Atul
7
@ Атул Да, здесь нужно равное. Потому что (new Boolean (true) == new Boolean (true)) равно .... false. Причина: Boolean - это просто класс, который может иметь несколько экземпляров, как и любой другой класс в Java.
AvrDragon
35
да, это позор, конструктор должен быть частным, так что это гарантировано, что это twingleton ...
Fortran
15
@fortran +1 для "twingleton".
Беннет МакЭлви
1
Нет абсолютно никакого смысла в использовании Apache BooleanUtils над этой идиомой.
StaxMan
82

Используйте Apache BooleanUtils .

(Если пиковая производительность является наиболее важным приоритетом в вашем проекте, посмотрите на один из других ответов для нативного решения, которое не требует включения внешней библиотеки.)

Не изобретай велосипед. Используйте то, что уже было построено и используйте isTrue():

BooleanUtils.isTrue( bool );

Проверяет, является ли Booleanзначение истинным, обрабатывает nullпутем возврата false.

Если вы не ограничены библиотеками, которые вам «разрешено» включать, есть множество отличных вспомогательных функций для всех видов сценариев использования, включая Booleansи Strings. Я предлагаю вам просмотреть различные библиотеки Apache и посмотреть, что они уже предлагают.

Джошуа Пинтер
источник
59
Изобретать колесо не так уж и плохо, когда альтернатива использует внешнюю библиотеку для чего-то столь же простого, как это.
Пол Манта
3
@PaulManta Я согласен, если это единственное, что вы когда- либо использовали в библиотеках Apache Utils, но предлагаемая идея состоит в том, чтобы «просмотреть» библиотеки, чтобы подвергнуть себя другим полезным функциям.
Джошуа Пинтер
1
Использование этих библиотек снижает производительность. Поэтому для таких базовых вещей, которые являются частью языка, вы не должны использовать библиотеки.
ACV
6
Эта библиотека заново изобретает колесо. Я стараюсь избегать таких библиотек, насколько это возможно.
mschonaker
3
@mschonaker Если Apache BooleanUtils заново изобретает колесо, что это за оригинальное колесо? Идея состоит в том, чтобы избежать создания множества вспомогательных функций, которые имитируют то, что уже было сделано в таких библиотеках, как эта. Я также использую toStringYesNoиз этой библиотеки во всех моих приложениях.
Джошуа Пинтер
13

Booleanтипы могут быть null. Вы должны сделать nullпроверку, как вы установили его null.

if (bool != null && bool)
{
  //DoSomething
}                   
fastcodejava
источник
3
Что не так с этим ответом? Это не проверка bool, которая будет выбрасывать исключение. Ненужные отрицательные голоса.
додексаэдр
2
Я согласен, что это вполне разумный ответ. Вы можете избавиться от обработки исключений, хотя.
Марво
14
Передача исключений не нужна, и кроме того, это делается таким образом, что это плохой пример для начинающих. Это заслуживает отрицательного ответа, ИМО. (Да ... Я знаю, что это происходит из примера кода, но повторение его в Ответе, кажется, подтверждает его.)
Стивен C
1
Что тогда правильно? Я не вижу вашего ответа здесь.
Марво
5
Правильный путь - тот, что выше ... нет обработки исключений. Кроме того, обработка исключений является слишком общей и не рекомендуется.
Веллвишер
8

Или с силой Java 8 Необязательно, вы также можете сделать такой трюк:

Optional.ofNullable(boolValue).orElse(false)

:)

provisota
источник
5

Boolean - это класс обёртки объекта для примитивного логического значения. Этот класс, как и любой класс, действительно может быть нулевым. Из соображений производительности и памяти всегда лучше использовать примитив.

Классы-обертки в Java API служат двум основным целям:

  1. Обеспечить механизм «обертывания» значений примитивов в объекте, чтобы примитивы могли быть включены в действия, зарезервированные для объектов, например, добавленные в Коллекции, или возвращенные из метода с возвращаемым значением объекта.
  2. Предоставить ассортимент служебных функций для примитивов. Большинство из этих функций связаны с различными преобразованиями: преобразованием примитивов в и из объектов String и преобразованием примитивов и объектов String в и из различных основ (или основ), таких как двоичные, восьмеричные и шестнадцатеричные.

http://en.wikipedia.org/wiki/Primitive_wrapper_class

Орлан
источник
0

так как ваша переменная bool указывает на нуль, вы всегда получите исключение NullPointerException, вам нужно сначала инициализировать переменную где-нибудь с ненулевым значением, а затем изменить его.

RicardoE
источник
1
Если бы это было просто, catchблок обработал бы исключение NullPointerException. Проблема здесь в том, что OP пытается распаковать нулевую ссылку в примитив.
Майк Адлер
«Вы будете всегда» - не всегда, за исключением примера, упрощенного кода, который ничего не делает между инициализацией переменной nullи ее тестированием. Предположительно реальный код не был бы таким простым, или весь ifтест можно было бы удалить.
nnnnnn