Коли слід використовувати нульові значення булевих значень?


159

Java booleanдозволяє значення trueі в falseтой час як Boolean дозволяє true, falseі null. Я почав перетворювати свій booleans в Booleans. Це може спричинити збої в таких тестах, як

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

під час тесту

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

здається надуманим і схильним до помилок.

Коли, якщо взагалі, це корисно використовувати Boolean s з нульовими значеннями? Якщо ніколи, то які основні переваги загорнутого предмета?

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


7
Іноді вам потрібно неініціалізований стан та встановлення Booleanзмінної до nullдовідки.
nhahtdh

2
"Завжди" трохи сильний, що я не наважуюся підтвердити, але я би сподівався на тест, nullякщо він справді використовується як 3-й стан.
nhahtdh

6
Чи є у вас привід перетворити булеві на булеві? Я б дотримувався примітивного типу і обертав його, лише якщо є вагомі причини для цього, наприклад, коли мені потрібно передати змінну за посиланням.
jpe

7
Ви також можете перевірити це: thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
biziclop

6
Немає такого поняття, як "нульове значення в булевому". A Boolean- це об'єкт, а a boolean- "скаляр". Якщо Booleanпосилання встановлено на нуль, це означає, що відповідний Booleanоб'єкт не існує. Ви не можете розмістити всередині чогось, що не існує.
Гарячі лизи

Відповіді:


244

Використовуйте, booleanа не Booleanкожен раз, коли зможете. Це дозволить уникнути багатьох NullPointerExceptions і зробить ваш код більш надійним.

Boolean корисно, наприклад

  • зберігати булеви в колекції (список, карта тощо)
  • представляти нульовий булевий (наприклад, з нульового булевого стовпчика в базі даних, наприклад). Нульове значення може означати "ми не знаємо, чи це правда чи неправда" в цьому контексті.
  • кожен раз, коли методу потрібен об'єкт як аргумент, і вам потрібно передати булеве значення. Наприклад, при використанні рефлексії або подібних методів MessageFormat.format().


31
Ваша друга куля - це справді серцевина правильної відповіді на це питання, я думаю.
Нільс Брінч

3
Ще одне використання Boolean, яке я мав, - це загальний параметр типу при розширенні загальних класів - тісно пов’язаних із пунктом 3.
Алекс

6
Перевантаження поняття нуля значенням, відмінним від "Всесвіт не знає", воно слабше, ніж використання 3 (або більше) перелічених перерахунків. Робить читання параметрів коду, що передає код, в метод також більш явним.
bluevector

16
Або №4: Boolean isSchrodinger‎CatAlive = null;(вибачте, не втримався;)).
Матьє

58

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

Я не бачу причин для перетворення booleanна, Booleanоскільки це створює додаткові накладні витрати на пам'ять, можливість NPE та менше набирати текст. Зазвичай я використовую незручно, BooleanUtils.isTrue()щоб трохи полегшити своє життяBoolean .

Єдиною причиною існування Booleanє можливість мати колекції Booleanтипу (дженерики не дозволяють boolean, як і всі інші примітиви).


1
Однак це зовнішня бібліотека (Apache commons).
nhahtdh

4
Для багатозначної логіки переважно використовувати переписки. Таким чином, Булеву слід залишити для (авто) бокс змінних для використання в структурах даних.
jpe

39
Під час використання Boolean зручним тестом на уникнення нульових винятків покажчика є Boolean.TRUE.equals(myBooleanObject)або Boolean.FALSE.equals(myBooleanObject).
Крістофер Пейзерт

10
Булевий об'єкт має лише два стани - trueі false. null- це не стан об'єкта, а скоріше стан посилання на об'єкт.
Гарячі лизи

2
Залиште в апаш-візі схожий на те, що "хтось може накрутити оцінку булів ... давайте зробимо isTrue()метод ...", що звучить як найглуміша кричуща річ в історії функцій утиліти. І все-таки якось корисно ... це найбільший wtf тут.
corsiKa

33

Вау, що на землі? Це просто я чи всі ці відповіді невірні чи принаймні оманливі?

Булівський клас - це обгортка навколо булевого примітивного типу. Використання цієї обгортки полягає в тому, щоб мати можливість передавати булевий метод методом, який приймає об'єкт або загальний характер. Тобто вектор.

Булевий об'єкт НІКОЛИ не може мати значення null. Якщо ваше посилання на булеве значення є нульовим, це просто означає, що ваш булевий формат ніколи не створювався.

Це може бути вам корисним: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Boolean.java

Нульова булева посилання повинна використовуватися лише для запуску аналогічної логіки, до якої у вас є будь-які інші нульові посилання. Використовувати його для трьох логік стану незграбно.

EDIT: зауважте, що Boolean a = true;це хибне твердження. Це дійсно дорівнює чимось ближчому. Boolean a = new Boolean(true); Будь ласка, дивіться автобокс тут: http://en.wikipedia.org/wiki/Boxing_%28computer_science%29#Autoboxing

Можливо, саме звідси походить велика плутанина.

EDIT2: Прочитайте коментарі нижче. Якщо у когось є ідея, як реструктуризувати мою відповідь, щоб це включити, будь ласка, зробіть це.


2
Я не розумію вашого твердження "Булевий НІКОЛИ не може мати значення" ". Я можу створити Boolean ( Boolean a = true;), а потім встановити null ( a = null;). Це може бути не елегантно чи мудро, але це можливо.
peter.murray.rust

7
Коли ви робите Boolean a; a - покажчик булевого об'єкта. Якщо ви a = null;не встановили Boolean на 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>

Я чітко написав "булева", а не " boolean" (розумова стилізація), тому що в Oracle ви зазвичай використовуєте значення char(1) null"T" і "F". Тож це може бути (наприклад, адаптером для сплячого режиму) нульовим :)
Grzegorz Grzybek

2
Яка база даних не дозволяє мати null для булевих? Якщо ви встановите стовпчик як нульовий, тип даних вже не має значення ...
Міхал Б.

@MichalB. Біт Sybase (і SQL Server) введіть infocenter.sybase.com/help/index.jsp?topic=/…
мммммм

@Mark - ні, SQL Server дозволяє дозволити нульовий
Девід М,

11

ВІДПОВІДЬ ДО ВЛАСНОГО ЗАПИТАННЯ: Я вважав, що було б корисно відповісти на моє власне запитання, оскільки я багато чого навчився з відповідей. Ця відповідь покликана допомогти тим, як я, - які не мають повного розуміння питань. Якщо я використовую неправильну мову, будь ласка, виправте мене.

  • Нульове "значення" не є значенням і принципово відрізняється від trueта false. Це відсутність вказівника на об’єкти. Тому думати, що булева 3-х оцінена, принципово неправильно
  • Синтаксис булевого скорочується і приховує той факт, що опорні точки на Об'єкти:

    Boolean a = true;

приховує той факт, що trueє об’єктом. Іншими еквівалентними завданнями можуть бути:

Boolean a = Boolean.TRUE;

або

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

    if (a) ...

відрізняється від більшості інших призначень і приховує той факт, що потенціал може бути посиланням на об'єкт або примітивом. Якщо об'єкт необхідно протестувати, nullщоб уникнути NPE. Мені психологічно простіше запам'ятати це, якщо є тест на рівність:

if (a == true) ...

де нас може запропонувати перевірити на нуль. Тож скорочена форма безпечна лише тоді, коли aє примітивом.

Для себе я зараз маю рекомендації:

  • Ніколи не використовуйте null для 3-значної логіки. Використовуйте лише істинне та хибне.
  • НІКОЛИ не повертайтеся Booleanз методу, як це було б null. Тільки повернення boolean.
  • Використовуйте лише Booleanдля загортання елементів у контейнери або аргументів методів, де потрібні об'єкти

5
Не використовуйте "новий булевий (будь-який)". Це дозволить створити новий булевий нагромадження. І все-таки булевий непорушний. Використовуйте "Boolean.valueOf (що завгодно)", який створить посилання, яке вказує на Boolean.TRUE або Boolean.False залежно від того, що саме.
simbo1905

1
Однією з багатьох проблем з Java (IMHO після 12 років) є непослідовність підходу до нульових значень, які також мають старі мови. Поглянувши на Scala, вона має концепцію введеного Варіанту, яка може бути нульовою або мати значення (підкласи None або Some). Тоді ви можете зателефонувати на myOption.getOrElse (defaultValue). Дивіться scala-lang.org/api/current/scala/Option.html у цій функції немає нічого складного. Однак, оскільки він вбудований у нову мову JVM, багато бібліотек використовують його. Це змушує масштаб "виправити" деякі з питань "минулого століття" Java, але він все ще компілюється в файли класів, які працюють на JRE.
simbo1905

10

Класи обгортки для примітивів можна використовувати там, де потрібні предмети, колекції - хороший зразок.

Уявіть собі , що вам потрібно для якої - то причини зберігати послідовність booleanв ArrayList, це може бути зроблено з боксу booleanвBoolean .

Про це є кілька слів тут

З документації:

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

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


3

Booleanобгортка корисна , коли ви хочете , чи було призначено значення чи ні , крім trueі false. Він має такі три стани:

  • Правда
  • помилковий
  • Не визначено, що таке null

Тоді як booleanє лише два штати:

  • Правда
  • помилковий

Вищенаведена різниця допоможе у Списках Booleanзначень, які можуть мати True, Falseабо Null.


Ні, він не має нульового стану, це посилання.
Matsemann

Що я мав на увазі, що Болеан може бути використаний для визначених True / False та Not Defined.
Рамеш ПВК

3

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


1

Основне призначення Boolean - нульове значення. Нульове значення говорить про те, що властивість не визначено , наприклад, взяти стовпчик нульового стовпця бази даних.

Якщо вам дійсно потрібно перетворити що-небудь з примітивного булевого в обертове булеве, тоді ви можете скористатися наступним для підтримки старого коду:

Boolean set = Boolean.FALSE; //set to default value primitive value (false)
...
if (set) ...

6
'Основне призначення - нульове значення'. Ні, головне призначення булевого - передати посилання на булеве як на об'єкт.
user606723

@ user606723 погодився, я мав на увазі справу бази даних, коли я писав.
JMelnik

1

У бульовій обгортці існує багато застосувань для значення ** null **! :)

Наприклад, у вас може бути у формі поле з назвою "інформаційний бюлетень", яке вказує, хоче або не хоче інформаційний бюлетень з вашого сайту. Якщо користувач не вибирає значення в цьому полі, ви можете застосувати поведінку за замовчуванням у цій ситуації (надіслати? Не надсилати?, Знову запитати? Тощо). Ясна річ, що не встановлено (або не вибрано чи ** null **), не є істинним чи хибним.

Але, якщо "не встановлено" не стосується вашої моделі, не змінюйте булеву примітиву;)


1

У суворому визначенні булевого елемента є лише два значення. У досконалому світі це було б правдою. У реальному світі елемент може бути відсутнім або невідомим. Як правило, це передбачає введення користувача. У системі, заснованої на екрані, це може бути вимушене редагуванням. У пакетному світі, що використовує або базу даних, або XML, елемент легко може бути відсутнім.

Отже, у неідеальному світі, в якому ми живемо, булевський об’єкт чудовий тим, що він може представляти відсутнє або невідоме стан як нульове. Зрештою, комп'ютери просто моделюють реальний світ і повинні враховувати всі можливі стани та обробляти їх викидами (переважно, оскільки є випадки використання, коли кидання винятку було б правильною відповіддю).

У моєму випадку об'єкт Boolean був ідеальною відповіддю, оскільки іноді у вхідного XML елемента не вистачало, і я все-таки можу отримати значення, призначити його булевим і потім перевірити наявність нуля, перш ніж намагатися з ним використовувати справжній чи хибний тест .

Всього мої 2 копійки.


1

На всі гарні відповіді вище, я просто збираюся навести конкретний приклад у HttpSessionкласі сервлетів Java . Сподіваюся, що цей приклад допомагає з’ясувати якесь питання, яке ви все ще можете мати.

Якщо вам потрібно зберегти та отримати значення для сеансу, ви використовуєте setAttribute(String, Object) та getAttribute(String, Object) метод. Тому для булевого значення ви змушені використовувати клас Boolean, якщо хочете зберегти його в http-сесії.

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

Останній рядок призведе до, NullPointerExceptionякщо значення атрибутів не встановлені. (що є причиною, що призвело мене до цієї посади). Таким чином, 3 логічний стан є для того, щоб залишитися, хочете ви його використовувати чи ні.


0

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

Однак прагматично вам доводиться час від часу використовувати булеві, але, як ви вже самі з’ясували, робота з булевими є більш схильною до помилок і громіздкішою. Тому я б запропонував використовувати булеві, де це можливо. Винятками з цього може бути застаріла база даних з незмінними булевими стовпцями, хоча я б спробував приховати це і в моєму відображенні.


Робота з Booleans є такою ж схильністю до помилок, як і з будь-яким іншим Об'єктом. До речі, посилання проти розповсюдження ІФ для перевірки типу, а не для загального використання. А в свою чергу, це "небезпечно", оскільки робить модифікації складнішими. Тож нічого із цього не буває в ІФ.
Містер Сміт

Не відповідь на запитання.
Мацеманн

@MisterSmith Imho булевий прапор часто застосовується як змінна перевірка типу, тому посилання може застосовуватися і тут. Це має бути лише натяком, що варто подумати про те, чи є булевим правильним інструментом у певній ситуації. Заява "уникати булевих" повністю, звичайно, є дуже радикальною і практично неможливою, тому я додав другий абзац. Я також додав "більш схильний до помилок і більш громіздкий", щоб уточнити речі.
Роланд Шнайдер

0

Булевий може бути дуже корисним, коли вам потрібно три стану. Як і в тестуванні програмного забезпечення, якщо тест пройдений, надішліть істинне, якщо не вдалося надіслати помилкове і якщо тестовий випадок перервано, надішліть null, який позначатиме тестовий випадок не виконаний.


2
Хіба б перерахунки не були найкращими для цього? На відміну від можливого отримання несподіваних NullPointerExceptions для клієнта, перерахунки чітко визначатимуть "стани"
Kartik Chugh

Завжди віддавайте перевагу замість булів у державних машинах. Ніколи не знаєш, коли до бізнес-вимоги прийде новий четвертий штат.
AnupamChugh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.