Kiedy należy używać zerowych wartości logicznych?

159

Java booleanpozwala na wartości true, a falsejednocześnie pozwala logiczna true, falsei null. Zacząłem konwertować moje booleans na Booleans. Może to powodować awarie w testach, takich jak

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

podczas testu

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

wydaje się wymyślony i podatny na błędy.

Kiedy, jeśli w ogóle, warto używać Booleans z wartościami null? Jeśli nigdy, to jakie są główne zalety opakowanego przedmiotu?

AKTUALIZACJA: Było tak wiele cennych odpowiedzi, że niektóre z nich podsumowałem we własnej odpowiedzi. Jestem co najwyżej średniozaawansowanym w Javie, więc starałem się pokazać rzeczy, które uważam za przydatne. Zwróć uwagę, że pytanie jest „niepoprawnie sformułowane” (wartość logiczna nie może „mieć wartości zerowej”), ale zostawiłem je na wypadek, gdyby inni mieli to samo błędne przekonanie

peter.murray.rust
źródło
7
Czasami potrzebujesz niezainicjowanego stanu, a ustawienie Booleanzmiennej nullpomaga.
nhahtdh
2
„Zawsze” jest trochę mocne, czego nie śmiem potwierdzać, ale spodziewałbym się testu, nulljeśli rzeczywiście jest używany jako trzeci stan.
nhahtdh
6
Czy masz powód, aby zmienić wartości logiczne na wartości logiczne? Trzymałbym się typu pierwotnego i zawijałbym go tylko wtedy, gdy jest ku temu dobry powód, np. Gdy muszę przekazać zmienną przez referencję.
jpe,
7
Również może chcesz sprawdzić to: thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
biziclop
6
Nie ma czegoś takiego jak „wartości zerowej w Boolean”. A Booleanjest obiektem, podczas gdy a booleanjest „skalarem”. Jeśli Booleanodniesienie ma wartość null, oznacza to, że odpowiedni Booleanobiekt nie istnieje. Nie możesz umieścić niczego w czymś, co nie istnieje.
Hot Licks

Odpowiedzi:

244

Używaj booleanzamiast za Booleankażdym razem, gdy możesz. Pozwoli to uniknąć wielu NullPointerExceptions i sprawi, że Twój kod będzie bardziej niezawodny.

Boolean jest przydatny na przykład

  • do przechowywania wartości logicznych w kolekcji (lista, mapa itp.)
  • do reprezentowania wartości logicznej dopuszczającej wartość null (pochodzącej na przykład z kolumny logicznej dopuszczającej wartość null w bazie danych). Wartość null może w tym kontekście oznaczać „nie wiemy, czy to prawda, czy fałsz”.
  • za każdym razem, gdy metoda wymaga obiektu jako argumentu i musisz przekazać wartość logiczną. Na przykład podczas korzystania z odbicia lub metod takich jak MessageFormat.format().
JB Nizet
źródło
35
Wartość zerowa w bazie danych może również oznaczać „FileNotFound”
Karl Johan,
31
Myślę, że twoja druga kula jest naprawdę sednem właściwej odpowiedzi na to pytanie.
Niels Brinch,
3
Innym zastosowaniem Boolean, które miałem, jest jako parametr typu ogólnego podczas rozszerzania klas ogólnych - blisko związany z punktem 3.
Alex
6
Przeciążanie pojęcia null znaczeniem innym niż „wszechświat nie wie” jest słabsze niż użycie wyliczenia o wartości 3 (lub więcej). Sprawia, że ​​odczyt kodu przekazującego parametry do metody jest również bardziej wyraźny.
bluevector
16
Lub # 4: Boolean isSchrodinger‎CatAlive = null;(przepraszam, nie mogłem się oprzeć;)).
Matthieu
58

Prawie nigdy nie używam, Booleanponieważ jego semantyka jest niejasna i niejasna. Zasadniczo masz logikę 3-stanową: prawda, fałsz lub nieznane. Czasami jest to przydatne, gdy np. Dałeś użytkownikowi wybór między dwiema wartościami, a użytkownik w ogóle nie odpowiedział i naprawdę chcesz poznać tę informację (pomyśl: kolumna bazy danych NULLable).

Nie widzę powodu, aby konwertować z booleanna, Booleanponieważ wprowadza to dodatkowe obciążenie pamięci, możliwość NPE i mniej pisania. Zwykle używam niezręczności, BooleanUtils.isTrue()aby ułatwić sobie życie Boolean.

Jedynym powodem istnienia Booleanjest możliwość posiadania kolekcji Booleantypu (typy generyczne nie pozwalają boolean, a także wszystkie inne prymitywy).

Tomasz Nurkiewicz
źródło
1
Jest to jednak biblioteka zewnętrzna (Apache commons).
nhahtdh
4
W przypadku logiki wielowartościowej zaleca się stosowanie wyliczeń. W związku z tym wartość logiczna powinna zostać pozostawiona dla (automatycznych) zmiennych pudełkowych do wykorzystania w strukturach danych.
jpe,
39
Podczas korzystania z wartości logicznej wygodnym testem unikającym wyjątków wskaźnika zerowego jest Boolean.TRUE.equals(myBooleanObject)lub Boolean.FALSE.equals(myBooleanObject).
Christopher Peisert,
10
Obiekt boolowski ma tylko dwa stany - truei false. nullto nie stan obiektu, ale raczej stan odwołania do obiektu.
Hot Licks
2
Pozostawmy apache commons w stylu „Ktoś może spieprzyć ocenianie wartości logicznych… zróbmy isTrue()metodę…”, co brzmi jak najgłupsza, dziwaczna rzecz w historii funkcji użytkowych. A jednak w jakiś sposób jest to przydatne ... to największy wtf tutaj.
corsiKa
33

Wow, co u licha? Czy to tylko ja, czy wszystkie te odpowiedzi są błędne lub przynajmniej mylące?

Klasa Boolean jest opakowaniem otaczającym typ pierwotny boolowski. Zastosowanie tego opakowania ma na celu przekazanie wartości logicznej w metodzie, która akceptuje obiekt lub rodzaj. Tj. Wektor.

Obiekt boolowski NIGDY nie może mieć wartości null. Jeśli twoje odniesienie do wartości Boolean jest zerowe, oznacza to po prostu, że twoja wartość Boolean nigdy nie została utworzona.

Może Ci się to przydać: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Boolean.java

Null Boolean Reference powinien być używany tylko do wyzwalania podobnej logiki, do której masz jakiekolwiek inne zerowe odniesienie. Używanie go do logiki trzech stanów jest niezdarne.

EDYCJA: uwaga, to Boolean a = true;jest mylące stwierdzenie. To naprawdę oznacza coś bliższego. Boolean a = new Boolean(true); Zobacz autoboxing tutaj: http://en.wikipedia.org/wiki/Boxing_%28computer_science%29#Autoboxing

Być może jest to przyczyna zamieszania.

EDYCJA2: Przeczytaj komentarze poniżej. Jeśli ktoś ma pomysł, jak zmienić moją odpowiedź, aby to uwzględnić, zrób to.

user606723
źródło
2
Nie rozumiem twojego stwierdzenia "Boolean NIGDY nie może mieć wartości null". Mogę utworzyć Boolean ( Boolean a = true;), a następnie ustawić wartość null ( a = null;). Może nie jest to eleganckie ani mądre, ale jest możliwe.
peter.murray.rust
7
Kiedy to zrobisz Boolean a; a jest wskaźnikiem do obiektu boolowskiego. Jeśli a = null;nie ustawiłeś swojej wartości logicznej na null, ustawiłeś odniesienie na null. Wykonaj Boolean a = null; a.booleanValue();W tym przypadku nigdy nawet nie utworzyłeś obiektu boolowskiego i dlatego zgłosi on wyjątek zerowy. Daj mi znać, jeśli potrzebujesz dalszych instrukcji.
user606723
Co więcej, kiedy to zrobisz Boolean a = true;, robi jakąś magię, która w rzeczywistości jest interpretowana jako Boolean a = new Boolean(true);To, prawdopodobnie nie do końca poprawne ze względu na wydajność, ale musisz zdać sobie sprawę, że wartość logiczna jest nadal przedmiotem.
user606723
7
@missingno, Cały kod, który dotyczy dowolnego obiektu, musi sobie z tym poradzić. Odwołanie do obiektu może mieć wartość null lub nie. To nie jest specjalny przypadek i nie wymaga specjalnego rozważenia.
user606723
3
Brakuje Ci mojego punktu @missingno. Zgadzam się, że musimy wziąć pod uwagę zerowe wartości odniesienia. Nigdy nie protestowałem przeciwko temu. Ale musimy to zrobić dla KAŻDEGO ODNIESIENIA DO OBIEKTU. Null Boolean odwołanie nie jest przypadkiem specjalnym. Dlatego też zerowe wartości Boolean nie wymagają specjalnego rozważania.
user606723
24

Istnieją trzy szybkie powody:

  • do reprezentowania wartości logicznych baz danych, które mogą być true, falselubnull
  • do reprezentowania xsd:booleanwartości schematu XML zadeklarowanych wxsd:nillable="true"
  • aby móc używać typów ogólnych: List<Boolean>- nie możesz używaćList<boolean>
Grzegorz Grzybek
źródło
Wyraźnie napisałem „boolean”, a nie „ boolean” (styl umysłu), ponieważ w Oracle zwykle używa char(1) nullsię wartości „T” i „F”. Więc może (z np. Adapterem typu Hibernate) być zerowe :)
Grzegorz Grzybek
2
Która baza danych nie zezwala na null dla wartości logicznych? Jeśli ustawisz kolumnę na wartość null, typ danych nie ma już znaczenia ...
Michal B.
@MichalB. Typ bitu Sybase (i SQL Server) infocenter.sybase.com/help/index.jsp?topic=/...
mmmmmm.
@Mark - nie, SQL Server zezwala na bit zerowalny - msdn.microsoft.com/en-us/library/ms177603.aspx
David M
11

ODPOWIEDŹ NA WŁASNE PYTANIE: Pomyślałem, że warto odpowiedzieć na moje własne pytanie, ponieważ wiele się nauczyłem z odpowiedzi. Ta odpowiedź ma pomóc tym - takim jak ja - którzy nie mają pełnego zrozumienia problemów. Jeśli używam niewłaściwego języka, popraw mnie.

  • Pusta „wartość” nie jest wartością i zasadniczo różni się od truei false. To brak wskaźnika do obiektów. Dlatego myślenie, że Boolean ma 3 wartości, jest zasadniczo błędne
  • Składnia Boolean jest skrócona i ukrywa fakt, że odniesienie wskazuje na Obiekty:

    Boolean a = true;

ukrywa fakt, że truejest przedmiotem. Inne równoważne zadania to:

Boolean a = Boolean.TRUE;

lub

Boolean a = new Boolean(true);
  • Skrócona składnia

    if (a) ...

różni się od większości innych przypisań i ukrywa fakt, że a może być odniesieniem do obiektu lub prymitywem. Jeśli obiekt jest potrzebny, nullaby uniknąć NPE. Dla mnie psychologicznie łatwiej to zapamiętać, jeśli istnieje test równości:

if (a == true) ...

gdzie możemy zostać poproszeni o przetestowanie wartości null. Tak więc skrócona forma jest bezpieczna tylko wtedy, gdy ajest prymitywna.

Dla siebie mam teraz zalecenia:

  • Nigdy nie używaj wartości null dla logiki o trzech wartościach. Używaj tylko prawdy i fałszu.
  • NIGDY nie wracaj Booleanz metody, jaka mogłaby być null. Tylko wróć boolean.
  • Używaj tylko Booleando zawijania elementów w kontenerach lub argumentów metod, w których wymagane są obiekty
peter.murray.rust
źródło
5
Nie używaj „new Boolean (cokolwiek)”. Spowoduje to utworzenie nowej wartości logicznej na stercie. Jednak Boolean jest niezmienny. Użyj „Boolean.valueOf (cokolwiek)”, co spowoduje utworzenie odniesienia wskazującego na Boolean.TRUE lub Boolean.False, w zależności od tego, cokolwiek.
simbo1905
1
Jednym z wielu problemów z Javą (IMHO po 12 latach) jest niespójność w podejściu do wartości zerowych, które mają również stare języki. Patrząc na Scalę, ma ona koncepcję wpisanej opcji, która może być pusta lub może mieć wartość (podklasy Brak lub Niektóre). Następnie możesz wywołać myOption.getOrElse (defaultValue). Zobacz scala-lang.org/api/current/scala/Option.html. Ta funkcja nie jest skomplikowana. Jednak ponieważ jest on wbudowany w nowy język JVM, korzysta z niego wiele bibliotek. To sprawia, że ​​skala „naprawia” niektóre z „ubiegłego wieku” problemu Javy, ale nadal kompiluje się do plików klas, które działają w środowisku JRE.
simbo1905
10

Klasy opakowujące dla prymitywów mogą być używane tam, gdzie wymagane są obiekty, a kolekcje są dobrym przykładem.

Wyobraź sobie, że potrzebujemy jakiegoś sklepu powodu sekwencję booleanw sposób ArrayList, można to zrobić przez boks booleanw Boolean.

Istnieje kilka słów o tym tutaj

Z dokumentacji:

Jak każdy programista Java wie, nie można umieścić wartości int (lub innej pierwotnej wartości) w kolekcji. Kolekcje mogą przechowywać tylko odniesienia do obiektów, więc musisz umieścić wartości pierwotne w odpowiedniej klasie opakowania (która jest Integer w przypadku int). Kiedy wyjmiesz obiekt z kolekcji, otrzymasz liczbę całkowitą, którą wstawiłeś; jeśli potrzebujesz int, musisz rozpakować liczbę Integer za pomocą metody intValue. Całe to pakowanie i rozpakowywanie jest uciążliwe i zaśmieca twój kod. Funkcja autoboxing i unboxing automatyzuje proces, eliminując ból i bałagan.

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

Francisco Spaeth
źródło
3

Booleanwrapper jest przydatny, gdy chcesz sprawdzić, czy wartość została przypisana, czy nie poza truei false. Ma następujące trzy stany:

  • Prawdziwe
  • Fałszywe
  • Nie określono, co jest null

Natomiast booleanma tylko dwa stany:

  • Prawdziwe
  • Fałszywe

Powyższa różnica sprawi, że będzie pomocna w Listach Booleanwartości, które mogą mieć True, Falselub Null.

Ramesh PVK
źródło
Nie, nie ma stanu zerowego, to jest odniesienie.
Matsemann
Miałem na myśli to, że Bolean może być używany do zdefiniowanych Prawda / Fałsz i Nie zdefiniowano.
Ramesh PVK
3

Przypuszczam, że w pewnym przypadku powinieneś mieć mechanizm rozróżniania pola boolowskiego, które już ustawiło wartość lub nie.

Thinhbk
źródło
1

Głównym celem Boolean jest wartość null. Wartość null mówi, że właściwość jest niezdefiniowana , na przykład weź kolumnę dopuszczającą wartość null bazy danych.

Jeśli naprawdę potrzebujesz przekonwertować wszystko z pierwotnych wartości logicznych na logiczne opakowujące, możesz użyć następującego kodu do obsługi starego kodu:

Boolean set = Boolean.FALSE; //set to default value primitive value (false)
...
if (set) ...
JMelnik
źródło
6
„Głównym celem jest wartość zerowa”. Nie, głównym celem Boolean jest przekazanie odniesienia do wartości boolowskiej jako obiektu.
user606723
@ user606723 zgodził się, kiedy pisałem, odnosiłem się do przypadku bazy danych w mojej głowie.
JMelnik
1

Wartość ** null ** w opakowaniu typu Boolean ma wiele zastosowań! :)

Na przykład możesz mieć w formularzu pole o nazwie „biuletyn”, które wskazuje, czy użytkownik chce, czy nie chce, aby otrzymywać biuletyn z Twojej witryny. Jeśli użytkownik nie wybierze wartości w tym polu, możesz zaimplementować domyślne zachowanie w tej sytuacji (wysłać? Nie wysyłać ?, pytanie ponownie? Itd.). Oczywiście, not set (or not selected or ** null **), to nie to samo co prawda czy fałsz.

Ale jeśli „nie ustawiono” nie ma zastosowania do Twojego modelu, nie zmieniaj prymitywu logicznego;)

dcasanueva
źródło
1

W ścisłej definicji elementu boolowskiego istnieją tylko dwie wartości. W idealnym świecie to byłaby prawda. W prawdziwym świecie element może brakować lub być nieznany. Zwykle wymaga to wprowadzenia danych przez użytkownika. W systemie opartym na ekranie może to zostać wymuszone przez edycję. W świecie wsadowym korzystającym z bazy danych lub danych wejściowych XML można łatwo brakować elementu.

Tak więc w niedoskonałym świecie, w którym żyjemy, obiekt boolowski jest świetny, ponieważ może reprezentować brakujący lub nieznany stan jako zerowy. W końcu komputery po prostu modelują świat rzeczywisty i powinny uwzględniać wszystkie możliwe stany i obsługiwać je z wyrzucaniem wyjątków (głównie dlatego, że istnieją przypadki użycia, w których zgłoszenie wyjątku byłoby poprawną odpowiedzią).

W moim przypadku obiekt Boolean był idealną odpowiedzią, ponieważ w wejściowym XMLu czasami brakowało elementu i nadal mogłem uzyskać wartość, przypisać ją do wartości Boolean, a następnie sprawdzić wartość null przed próbą użycia z nim testu true lub false .

Tylko moje 2 centy.

user3228876
źródło
1

Dla wszystkich dobrych odpowiedzi powyżej, podam konkretny przykład w HttpSessionklasie serwletów Java . Mam nadzieję, że ten przykład pomoże w wyjaśnieniu niektórych pytań, które nadal możesz mieć.

Jeśli chcesz zapisać i pobrać wartości dla sesji, użyj setAttributemetody (String, Object) i getAttribute(String, Object). Tak więc w przypadku wartości logicznej jesteś zmuszony użyć klasy Boolean, jeśli chcesz przechowywać ją w sesji http.

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

Ostatnia linia spowoduje a, NullPointerExceptionjeśli wartości atrybutów nie są ustawione. (co jest powodem doprowadziło mnie do tego postu). Tak więc stan logiczny 3 pozostanie, niezależnie od tego, czy wolisz go używać, czy nie.

Wacker
źródło
0

Najlepszym sposobem byłoby całkowite uniknięcie wartości logicznych, ponieważ każda wartość logiczna implikuje, że w innym miejscu kodu znajduje się instrukcja warunkowa (patrz http://www.antiifcampaign.com/ i to pytanie: Czy możesz napisać dowolny algorytm bez instrukcji if ? ).

Jednak pragmatycznie trzeba od czasu do czasu używać wartości logicznych, ale jak już sam się przekonałeś, radzenie sobie z booleanami jest bardziej podatne na błędy i bardziej uciążliwe. Dlatego sugerowałbym używanie wartości logicznych, gdy tylko jest to możliwe. Wyjątkiem może być starsza baza danych z kolumnami logicznymi dopuszczającymi wartość zerową, chociaż próbowałbym to również ukryć w moim mapowaniu.

Roland Schneider
źródło
Radzenie sobie z wartościami logicznymi jest równie podatne na błędy, jak w przypadku innych obiektów. Przy okazji, link jest przeciwko rozpowszechnianiu IF do sprawdzania typu, a nie do ogólnego użytku. A to z kolei jest „niebezpieczne”, ponieważ utrudnia modyfikacje. Nie ma więc nic złego w IF jako takim.
Mister Smith
Brak odpowiedzi na pytanie.
Matsemann
@MisterSmith Imho flaga boolowska jest często niewłaściwie używana jako zmienna sprawdzająca typ, więc link może mieć zastosowanie również tutaj. Powinna być tylko wskazówką, że należy pomyśleć o tym, czy boolean jest odpowiednim narzędziem w określonej sytuacji. Stwierdzenie „całkowicie unikaj wartości logicznych” jest oczywiście bardzo radykalne i praktycznie niemożliwe, dlatego dodałem drugi akapit. Dodałem również „bardziej podatne na błędy i uciążliwe”, aby wyjaśnić sprawę.
Roland Schneider
0

Wartość logiczna może być bardzo pomocna, gdy potrzebujesz trzech stanów. Podobnie jak w testowaniu oprogramowania, jeśli Test zostanie zaliczony, wyślij true, jeśli nie powiodło się, wyślij false, a jeśli przypadek testowy zostanie przerwany, wyślij null, co oznacza, że ​​przypadek testowy nie został wykonany.

Aamir
źródło
2
Czy wyliczenia nie byłyby do tego najlepsze? W przeciwieństwie do możliwych nieoczekiwanych wyjątków NullPointerExceptions dla klienta, wyliczenia wyraźnie definiowałyby „stany”
Kartik Chugh,
Zawsze preferuj wyliczenia zamiast wartości logicznych w automatach stanowych. Nigdy nie wiadomo, kiedy w wymaganiach biznesowych pojawia się nowy czwarty stan.
AnupamChugh