Когда следует использовать нулевые значения Boolean?

159

Java booleanпозволяет значения trueи в falseто время как Boolean позволяет true, falseи null. Я начал конвертировать мои booleans в Booleans. Это может вызвать сбои в таких тестах, как

Boolean set = null;
...
if (set) ...

пока тест

if (set != null && set) ...

кажется надуманным и подверженным ошибкам.

Когда, если вообще, полезно ли использовать Booleans с нулевыми значениями? Если никогда, то каковы основные преимущества обернутого объекта?

ОБНОВЛЕНИЕ: было так много ценных ответов, что я суммировал некоторые из них в своем собственном ответе. Я в лучшем случае являюсь промежуточным звеном в Java, поэтому я попытался показать то, что мне показалось полезным. Обратите внимание, что вопрос «неправильно сформулирован» (логическое значение не может иметь «нулевое значение»), но я оставил его на тот случай, если у других такое же заблуждение

peter.murray.rust
источник
7
Иногда требуется неинициализированное состояние и установка Booleanпеременной для nullподсказок.
nhahtdh
3
«Всегда» немного сильное, что я не осмеливаюсь подтверждать, но я ожидаю, что тест будет проверен, nullесли он действительно используется в качестве третьего состояния.
nhahtdh
6
У вас есть причина для преобразования логических значений в логические? Я бы придерживался примитивного типа и переносил его, только если для этого есть веская причина, например, когда мне нужно передать переменную по ссылке.
Jpe
7
Вы также можете проверить это: thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
biziclop
6
Нет такой вещи как «нулевое значение в логическом значении ». А Boolean- это объект, а А boolean- это «скаляр». Если Booleanссылка имеет значение null, это означает, что соответствующий Booleanобъект не существует. Вы не можете поместить что-то внутри чего-то, что не существует.
Hot Licks

Ответы:

244

Используйте, booleanа не Booleanкаждый раз, когда вы можете. Это позволит избежать многих NullPointerExceptionошибок и сделает ваш код более надежным.

Boolean полезно, например

  • хранить логические значения в коллекции (Список, Карта и т. д.)
  • для представления логического значения, допускающего значение NULL (например, из логического столбца, допускающего значение NULL) в базе данных. В этом контексте нулевое значение может означать «мы не знаем, правда это или нет».
  • каждый раз, когда методу требуется аргумент Object, и вам нужно передать логическое значение. Например, при использовании отражения или методов вроде MessageFormat.format().
Дж. Б. Низет
источник
35
Нулевое значение в базе данных также может означать «FileNotFound»
Карл Йохан
31
Думаю, ваша вторая пуля действительно является основой правильного ответа на этот вопрос.
Нильс Бринч
3
Другое использование для Boolean, которое у меня было, - это параметр универсального типа при расширении универсальных классов - тесно связанный с пунктом 3.
Алекс
6
Перегрузка понятия нуля значением, отличным от «вселенная не знает», оно слабее, чем использование 3 (или более) значного перечисления. Делает чтение кода, передавая параметры в метод, также более явным.
bluevector
16
Или # 4: Boolean isSchrodinger‎CatAlive = null;(извините, не смог устоять;)).
Матье
58

Я почти никогда не использую, Booleanпотому что его семантика расплывчата и неясна. В основном у вас есть логика с тремя состояниями: истина, ложь или неизвестность. Иногда полезно использовать его, когда, например, вы дали пользователю выбор между двумя значениями, а пользователь вообще не ответил, и вы действительно хотите узнать эту информацию (подумайте: столбец базы данных NULLable).

Я не вижу причин для конвертации booleanв, Booleanпоскольку это приводит к дополнительным затратам памяти, возможности NPE и меньшему количеству ввода. Обычно я использую неловко, BooleanUtils.isTrue()чтобы немного облегчить мне жизнь Boolean.

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

Томаш Нуркевич
источник
1
Это внешняя библиотека (Apache commons).
nhahtdh
4
Для многозначной логики предпочтительно использовать перечисления. Таким образом, Boolean следует оставить для (авто) переменных бокса для использования в структурах данных.
jpe
39
При использовании Boolean удобным тестом для исключения исключений нулевого указателя является Boolean.TRUE.equals(myBooleanObject)или Boolean.FALSE.equals(myBooleanObject).
Кристофер Пайзерт
10
Логический объект имеет только два состояния - trueи false. nullэто не состояние объекта, а состояние ссылки на объект.
Hot Licks
2
Оставьте apache commons похожим на «Кто-то может испортить вычисление логических значений ... давайте создадим isTrue()метод ...», что звучит как самая глупая вещь в истории вспомогательных функций. И все же, так или иначе, это полезно ... это самый большой вес здесь.
CorsiKa
33

Вау, что на земле? Это только я или все эти ответы неверны или, по крайней мере, вводят в заблуждение?

Логический класс - это оболочка вокруг логического примитивного типа. Использование этой обертки позволяет передавать логическое значение в методе, который принимает объект или универсальный объект. Т.е. вектор.

Логический объект НИКОГДА не может иметь значение null. Если ваша ссылка на логическое значение пуста, это просто означает, что ваш логический аргумент никогда не создавался.

Вы можете найти это полезным: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Boolean.java

Нулевая логическая ссылка должна использоваться только для запуска аналогичной логики, к которой у вас есть любая другая нулевая ссылка. Использование его для логики трех состояний неуклюже.

РЕДАКТИРОВАТЬ: обратите внимание, Boolean a = true;это вводящее в заблуждение утверждение. Это действительно что-то ближе к. Boolean a = new Boolean(true); Пожалуйста, посмотрите автобокс здесь: http://en.wikipedia.org/wiki/Boxing_%28computer_science%29#Autoboxing

Возможно, отсюда и большая часть путаницы.

РЕДАКТИРОВАТЬ 2: Пожалуйста, прочитайте комментарии ниже. Если у кого-то есть идея, как изменить мой ответ, чтобы включить это, сделайте это.

user606723
источник
2
Я не понимаю ваше утверждение "Булево значение НИКОГДА не может иметь значение null". Я могу создать Boolean ( Boolean a = true;) и затем установить значение null ( a = null;). Это может быть не элегантно или мудро, но возможно.
peter.murray.rust
7
Когда вы делаете Boolean a; a - указатель на логический объект. Если вы a = null;не установили для своего логического значения значение null, то для вашей ссылки будет установлено значение null. У Boolean a = null; a.booleanValue();В этом случае, вы никогда даже создали булев объект и , следовательно , он будет бросать NullPointerException. Дайте мне знать, если вам нужна дополнительная инструкция.
user606723
Кроме того, когда вы это делаете Boolean a = true;, он выполняет какую-то магию, которая на самом деле интерпретируется как Boolean a = new Boolean(true);Thats, возможно, не совсем корректно по соображениям производительности, но вы должны понимать, что Boolean по-прежнему является объектом.
user606723
7
@missingno, весь код, который имеет дело с любым объектом, должен иметь дело с этим. Ссылка на объект может быть либо нулевой, либо нет. Это не особый случай и не требует особого рассмотрения.
user606723
3
Ты упускаешь мою точку зрения @missingno. Я согласен, что нам нужно учитывать нулевые ссылочные значения. Я никогда не спорил против этого. Но мы должны сделать это для ЛЮБОЙ ОБЪЕКТНОЙ ССЫЛКИ. Нулевая логическая ссылка не является особым случаем. И поэтому нулевые булевы ссылочные значения не требуют специального рассмотрения.
user606723
24

Есть три быстрые причины:

  • представлять логические значения базы данных, которые могут быть true, falseилиnull
  • представлять значения XML-схемы, xsd:booleanобъявленные сxsd:nillable="true"
  • чтобы иметь возможность использовать общие типы: List<Boolean>- вы не можете использоватьList<boolean>
Grzegorz Grzybek
источник
Я явно написал «логическое», а не « boolean» (стиль мышления), потому что в Oracle вы обычно используете значения char(1) null«T» и «F». Так что это может (например, с адаптером типа Hibernate) быть нулевым :)
Grzegorz Grzybek
2
Какая база данных не допускает null для логического значения? Если вы установите для столбца обнуляемый тип данных больше не будет иметь значения ...
Михал Б.
@MichalB. Sybase (и SQL Server) битовый тип infocenter.sybase.com/help/index.jsp?topic=/…
мммммм
@Mark - нет, SQL Server действительно допускает обнуляемый бит - msdn.microsoft.com/en-us/library/ms177603.aspx
Дэвид М
11

ОТВЕТ НА СВОЙ ВОПРОС: Я подумал, что было бы полезно ответить на мой собственный вопрос, поскольку я многому научился из ответов. Этот ответ призван помочь тем, кто, как и я, не имеет полного понимания проблем. Если я использую неправильный язык, пожалуйста, поправьте меня.

  • Нулевое «значение» не является значением и принципиально отличается от trueи false. Это отсутствие указателя на объекты. Поэтому думать, что логическое 3-значное, в корне неверно
  • Синтаксис Boolean сокращен и скрывает тот факт, что ссылка указывает на Object:

    Boolean a = true;

скрывает тот факт, что trueявляется объектом. Другие эквивалентные назначения могут быть:

Boolean a = Boolean.TRUE;

или

Boolean a = new Boolean(true);
  • Сокращенный синтаксис

    if (a) ...

отличается от большинства других назначений и скрывает тот факт, что a может быть ссылкой на объект или примитивом. Если объект необходимо проверить, nullчтобы избежать NPE. Мне психологически легче запомнить это, если есть тест на равенство:

if (a == true) ...

где нам может быть предложено проверить на ноль. Таким образом, сокращенная форма безопасна только тогда, когда aона примитивна.

Для себя у меня теперь есть рекомендации:

  • Никогда не используйте нуль для 3-значной логики. Используйте только истину и ложь.
  • НИКОГДА не возвращайтесь Booleanиз метода, каким он мог бы быть null. Только вернись boolean.
  • Использовать только Booleanдля обертывания элементов в контейнерах или аргументов методов, где требуются объекты
peter.murray.rust
источник
5
Не используйте «новый логический (любой)». Это создаст экземпляр нового логического значения в куче. Тем не менее, логическое значение является неизменным. Используйте «Boolean.valueOf (что угодно)», который создаст ссылку, которая указывает либо на Boolean.TRUE, либо на Boolean.False, в зависимости от чего бы то ни было.
simbo1905
1
Одной из многих проблем с Java (IMHO после 12 лет) является несоответствие подхода к нулевым значениям, которое также имеют старые языки. Взглянув на Scala, он имеет концепцию типизированного Option, который может быть нулевым или иметь значение (подклассы None или Some). Затем вы можете вызвать myOption.getOrElse (defaultValue). См. Scala-lang.org/api/current/scala/Option.html. В этой функции нет ничего сложного. Тем не менее, поскольку он встроен в новый язык JVM, многие библиотеки используют его. Это делает масштабирование «исправлением» некоторых проблем Java в «прошлом веке», но все равно компилируется в файлы классов, которые работают на JRE.
simbo1905
10

Классы обертки для примитивов могут использоваться там, где требуются объекты, и коллекции являются хорошим примером.

Представьте, что вам нужно по какой-то причине сохранить последовательность booleanв ArrayList, это можно сделать, поместив booleanв бокс Boolean.

Существует несколько слов об этом здесь

Из документации:

Как знает любой Java-программист, вы не можете поместить int (или другое примитивное значение) в коллекцию. Коллекции могут содержать только ссылки на объекты, поэтому вы должны поместить значения примитивов в соответствующий класс-оболочку (в случае int это Integer). Когда вы вынимаете объект из коллекции, вы получаете целое число, которое вы вставили; если вам нужно int, вы должны распаковать Integer, используя метод intValue. Весь этот бокс и распаковка являются болью и загромождают ваш код. Функция автобоксирования и распаковки автоматизирует процесс, устраняя боль и беспорядок.

http://docs.oracle.com/javase/1.5.0/docs/guide/language/autoboxing.html

Франсиско Спает
источник
3

Booleanобертка полезна , когда вы хотите , было ли назначено значение или нет , кроме trueи false. Он имеет следующие три состояния:

  • Правда
  • Ложь
  • Не определено что null

Принимая во внимание, что booleanесть только два государства:

  • Правда
  • Ложь

Выше разница будет сделать его полезным в списках Booleanзначений, которые могут иметь True, Falseили Null.

Рамеш ПВК
источник
Нет, у него нет нулевого состояния, это ссылка.
Мацеманн
Я имел в виду, что Bolean можно использовать для определения True / False и Not Defined.
Рамеш ПВК
3

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

Thinhbk
источник
1

Основным назначением для логического значения является нулевое значение. Нулевое значение говорит о том, что свойство не определено , например, взять столбец базы данных, обнуляемый.

Если вам действительно нужно преобразовать все из примитивного логического значения в логическое значение оболочки, то вы можете использовать следующее для поддержки старого кода:

Boolean set = Boolean.FALSE; //set to default value primitive value (false)
...
if (set) ...
JMelnik
источник
6
«Основная цель - нулевое значение». Нет, основная цель Boolean - передать ссылку на Boolean как объект.
user606723
@ user606723 согласился, я имел в виду случай с базой данных, когда писал.
JMelnik
1

Существует множество вариантов использования значения ** null ** в булевой оболочке! :)

Например, вы можете иметь в форме поле с именем «информационный бюллетень», которое указывает, хочет ли пользователь получать информационный бюллетень с вашего сайта или нет. Если пользователь не выбирает значение в этом поле, вы можете реализовать поведение по умолчанию для этой ситуации (отправить? Не отправлять?, Вопрос снова? И т. Д.). Понятно, что не установлено (или не выбрано или ** null **), это не то же самое, что true или false.

Но, если «не установлено» не относится к вашей модели, не меняйте логический примитив;)

dcasanueva
источник
1

В строгом определении логического элемента есть только два значения. В идеальном мире это было бы правдой. В реальном мире элемент может отсутствовать или быть неизвестным. Как правило, это включает в себя пользовательский ввод. В экранной системе это может быть вызвано редактированием. В пакетном мире, использующем либо базу данных, либо вход XML, элемент может легко отсутствовать.

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

В моем случае логический объект был идеальным ответом, поскольку во входном XML иногда отсутствовал элемент, и я все еще мог получить значение, присвоить ему логическое значение, а затем проверить на нулевое значение, прежде чем пытаться использовать с ним истинный или ложный тест. ,

Просто мои 2 цента.

user3228876
источник
1

Для всех хороших ответов выше, я просто приведу конкретный пример в HttpSessionклассе сервлетов Java . Надеюсь, этот пример поможет прояснить некоторые вопросы, которые могут у вас возникнуть.

Если вам нужно сохранить и получить значения для сеанса, вы используете setAttribute(String, Object) и getAttribute(String, Object) метод. Поэтому для логического значения вы вынуждены использовать логический класс, если хотите сохранить его в сеансе http.

HttpSession sess = request.getSession(false);
Boolean isAdmin = (Boolean) sess.getAttribute("admin");
if (! isAdmin) ...

Последняя строка будет вызывать, NullPointerExceptionесли значения атрибута не установлены. (что и привело меня к этому посту). Таким образом, 3 логических состояния здесь, чтобы остаться, предпочитаете ли вы использовать его или нет.

Wacker
источник
0

Лучшим способом было бы полностью избежать логических выражений, поскольку каждое логическое подразумевает, что у вас есть условный оператор где-либо еще в вашем коде (см. Http://www.antiifcampaign.com/ и этот вопрос: можете ли вы написать любой алгоритм без оператора if ? )

Тем не менее, прагматически вы должны время от времени использовать логические значения, но, как вы уже убедились, работа с логическими значениями более подвержена ошибкам и более обременительна. Поэтому я бы предложил использовать логические значения везде, где это возможно. Исключениями из этого может быть устаревшая база данных с обнуляемыми логическими столбцами, хотя я бы попытался скрыть это и в своем отображении.

Роланд Шнайдер
источник
Работа с логическими значениями так же подвержена ошибкам, как и работа с любым другим объектом. Кстати, ссылка против распространения IF для проверки типа, а не для общего использования. И, в свою очередь, это «опасно», потому что это делает модификации более сложными. Так что нет ничего плохого в IF как таковых.
Мистер Смит
Не ответ на вопрос.
Мацеманн
@MisterSmith Imho логический флаг часто неправильно используется как переменная проверки типа, поэтому ссылка также может применяться здесь. Это должен быть просто намек на то, что следует подумать о том, является ли логическое значение правильным инструментом в определенной ситуации. Утверждение «полностью избегать логических выражений», конечно, очень радикально и практически невозможно, поэтому я добавил второй абзац. Я также добавил «более подверженный ошибкам и более громоздкий», чтобы прояснить ситуацию.
Роланд Шнайдер
0

Логическое значение может быть очень полезным, когда вам нужно три состояния. Как и в тестировании программного обеспечения, если Тест пройден, отправьте true, если не удалось отправить false и если тестовый случай прерван, отправьте null, что будет означать, что тестовый случай не выполнен.

Аамир
источник
2
Разве перечисления не будут лучше для этого? В отличие от возможных неожиданных исключений NullPointerException для клиента, перечисления явно определяют «состояния»
Kartik Chugh
Всегда предпочитайте перечисления вместо логических значений в конечных автоматах. Вы никогда не знаете, когда в бизнес-требования приходит новое четвертое государство.
AnupamChugh