Quando valores nulos de booleanos devem ser usados?

159

Java booleanpermite que os valores de truee falseenquanto booleana permite true, falsee null. Comecei a converter meus booleans em Booleans. Isso pode causar falhas em testes como

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

enquanto o teste

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

parece artificial e propenso a erros.

Quando, se for o caso, é útil usar Booleans com valores nulos? Se nunca, então quais são as principais vantagens do objeto empacotado?

ATUALIZAÇÃO: Houve tantas respostas valiosas que resumi algumas delas em minha própria resposta. Eu sou, na melhor das hipóteses, um intermediário em Java, então tentei mostrar as coisas que acho úteis. Observe que a pergunta está "formulada incorretamente" (o booleano não pode "ter um valor nulo"), mas eu a deixei no caso de outras pessoas terem o mesmo equívoco.

peter.murray.rust
fonte
7
Às vezes, você deseja um estado não inicializado e a configuração de Booleanvariável como nullhelp.
N
2
"Always" é um pouco forte que eu não ouso confirmar, mas eu esperaria um teste nullse ele realmente for usado como um terceiro estado.
N
6
Você tem um motivo para converter booleanos em booleanos? Eu continuaria com o tipo primitivo e o agruparia apenas se houver um bom motivo para fazê-lo, por exemplo, quando precisar passar uma variável por referência.
Jpe 25/06
7
Você também pode querer verificar para fora este: thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
biziclop
6
Não existe um "valor nulo em um booleano". A Booleané um objeto, enquanto a booleané um "escalar". Se uma Booleanreferência for definida como nula, isso significa que o Booleanobjeto correspondente não existe. Você não pode colocar nada dentro de algo que não existe.
Hot Licks

Respostas:

244

Use booleane não Booleansempre que puder. Isso evitará muitos se NullPointerExceptiontornará seu código mais robusto.

Boolean é útil, por exemplo

  • para armazenar booleanos em uma coleção (lista, mapa etc.)
  • para representar um booleano anulável (proveniente de uma coluna booleana anulável em um banco de dados, por exemplo). O valor nulo pode significar "não sabemos se é verdadeiro ou falso" neste contexto.
  • toda vez que um método precisa de um objeto como argumento e você precisa passar um valor booleano. Por exemplo, ao usar reflexão ou métodos como MessageFormat.format().
JB Nizet
fonte
35
Um valor nulo no banco de dados também pode significar "FileNotFound"
Karl Johan
31
Sua segunda bala é realmente o núcleo da resposta certa para essa pergunta, eu acho.
Niels Brinch
3
Outro uso para booleano que eu tive é como um parâmetro de tipo genérico ao estender classes genéricas - intimamente relacionado com o ponto 3.
Alex
6
Sobrecarregar o conceito de null com um significado diferente de "o universo não o conhece" é mais fraco do que usar um enum com valor 3 (ou mais). Torna a leitura de código que passa parâmetros no método mais explícita também.
26412 bluevector
16
Ou # 4: Boolean isSchrodinger‎CatAlive = null;(desculpe, não pude resistir;)).
Matthieu
58

Eu quase nunca uso Booleanporque sua semântica é vaga e obscura. Basicamente, você tem lógica de três estados: verdadeiro, falso ou desconhecido. Às vezes, é útil usá-lo quando, por exemplo, você deu ao usuário uma escolha entre dois valores e o usuário não respondeu nada e realmente deseja saber essas informações (pense: coluna NULLable do banco de dados).

Não vejo razão para converter de booleanpara Boolean, pois introduz sobrecarga de memória extra, possibilidade de NPE e menos digitação. Normalmente eu uso estranho BooleanUtils.isTrue()para tornar minha vida um pouco mais fácil Boolean.

A única razão para a existência de Booleané a capacidade de ter coleções do Booleantipo (os genéricos não permitem boolean, assim como todas as outras primitivas).

Tomasz Nurkiewicz
fonte
1
É uma biblioteca externa (Apache commons), no entanto.
N
4
Para lógica de valores múltiplos, é preferível usar enumerações. Portanto, booleano deve ser deixado para as variáveis ​​(auto) de boxe para uso em estruturas de dados.
Jpe 25/06
39
Ao usar booleano, um teste conveniente para evitar exceções de ponteiro nulo é Boolean.TRUE.equals(myBooleanObject)ou Boolean.FALSE.equals(myBooleanObject).
Christopher Peisert
10
Um objeto booleano possui apenas dois estados - truee false. nãonull é um estado do objeto, mas um estado da referência do objeto.
Hot Licks
2
Deixe para apache commons ser como "Alguém pode estragar a avaliação de booleanos ... vamos criar um isTrue()método ..." que soa como a coisa mais idiota da história das funções utilitárias. E, no entanto, de alguma forma, é útil ... esse é o maior peso aqui.
corsiKa
33

Uau, o que diabos? Sou apenas eu ou todas essas respostas estão erradas ou pelo menos enganosas?

A classe booleana é um wrapper em torno do tipo primitivo booleano. O uso desse wrapper é capaz de transmitir um booleano em um método que aceita um objeto ou genérico. Ou seja, vetor.

Um objeto booleano nunca pode ter um valor nulo. Se sua referência a um booleano for nula, significa simplesmente que seu booleano nunca foi criado.

Você pode achar isso útil: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Boolean.java

Uma referência booleana nula deve ser usada apenas para acionar lógica semelhante à qual você tem qualquer outra referência nula. Usá-lo para lógica de três estados é desajeitado.

EDIT: aviso, isso Boolean a = true;é uma declaração enganosa. Isso realmente é igual a algo mais próximo de Boolean a = new Boolean(true); Por favor, veja autobox aqui: http://en.wikipedia.org/wiki/Boxing_%28computer_science%29#Autoboxing

Talvez seja daí que vem grande parte da confusão.

EDIT2: Por favor, leia os comentários abaixo. Se alguém tiver uma idéia de como reestruturar minha resposta para incorporar isso, faça-o.

user606723
fonte
2
Eu não entendo sua afirmação "Um booleano nunca pode ter um valor nulo". Eu posso criar um Boolean ( Boolean a = true;) e depois definir um como null ( a = null;). Pode não ser elegante ou sábio, mas é possível.
Peter.murray.rust
7
Quando você faz Boolean a; a é um ponteiro para um objeto booleano. Se você a = null;não definiu seu booleano como nulo, definiu sua referência como nulo. Faça Boolean a = null; a.booleanValue();Neste caso, você nunca criou um objeto Boolean e, portanto, ele vai lançar um NullPointerException. Entre em contato se precisar de mais instruções.
user606723
Além disso, quando você faz isso Boolean a = true;, ele faz algum tipo de mágica que realmente é interpretada como Boolean a = new Boolean(true);provavelmente não está completamente correta por razões de desempenho, mas você deve perceber que o booleano ainda é um objeto.
user606723
7
@ missingno, todo o código que lida com qualquer objeto tem que lidar com isso. Uma referência de objeto pode ser nula ou não. Este não é um caso especial e não requer consideração especial.
user606723
3
Você está perdendo o meu argumento @missingno. Concordo que precisamos considerar valores de referência nulos. Eu nunca estava argumentando contra isso. Mas precisamos fazer isso por QUALQUER REFERÊNCIA DE OBJETO. Uma referência booleana nula não é um caso especial. E, portanto, valores de referência booleanos nulos não requerem consideração especial.
user606723
24

Há três razões rápidas:

  • para representar valores booleanos de banco de dados, que pode ser true, falseounull
  • para representar os xsd:booleanvalores do esquema XML declarados comxsd:nillable="true"
  • para poder usar tipos genéricos: List<Boolean>- você não pode usarList<boolean>
Grzegorz Grzybek
fonte
Eu escrevi explicitamente "boolean", não " boolean" (estilo da mente), porque no Oracle você costuma usar char(1) nullcom os valores 'T' e 'F'. Por isso, pode (com, por exemplo, tipo de adaptador de hibernação) ser nula :)
Grzegorz Grzybek
2
Qual banco de dados não permite nulo para booleano? Se você definir a coluna para ser anulável, o tipo de dados não importa mais ...
Michal B.
@MichalB. Sybase (e SQL Server) Tipo pouco infocenter.sybase.com/help/index.jsp?topic=/...
mmmmmm
@ Mark - não, o SQL Server permite um bit anulável - msdn.microsoft.com/en-us/library/ms177603.aspx
David M
11

RESPOSTA À PRÓPRIA PERGUNTA: Pensei que seria útil responder minha própria pergunta, pois aprendi muito com as respostas. Esta resposta tem como objetivo ajudar aqueles - como eu - que não têm um entendimento completo dos problemas. Se eu usar um idioma incorreto, corrija-me.

  • O "valor" nulo não é um valor e é fundamentalmente diferente de truee false. É a ausência de um ponteiro para objetos. Portanto, pensar que Booleano tem 3 valores é fundamentalmente errado
  • A sintaxe para Boolean é abreviada e oculta o fato de que a referência aponta para Objetos:

    Boolean a = true;

esconde o fato de que trueé um objeto. Outras atribuições equivalentes podem ser:

Boolean a = Boolean.TRUE;

ou

Boolean a = new Boolean(true);
  • A sintaxe abreviada

    if (a) ...

é diferente da maioria das outras atribuições e oculta o fato de que a pode ser uma referência a um objeto ou uma primitiva. Se um objeto é necessário testar para nullevitar o NPE. Para mim, é psicologicamente mais fácil lembrar disso se houver um teste de igualdade:

if (a == true) ...

onde podemos ser solicitados a testar nulos. Portanto, a forma abreviada só é segura quando aé primitiva.

Para mim, agora tenho as recomendações:

  • Nunca use null para uma lógica de 3 valores. Use apenas verdadeiro e falso.
  • NUNCA retorne Booleande um método como poderia ser null. Apenas retorne boolean.
  • Use apenas Booleanpara agrupar elementos em contêineres ou argumentos para métodos em que objetos são necessários
peter.murray.rust
fonte
5
Não use "novo booleano (qualquer que seja)". Isso instancia um novo booleano na pilha. No entanto, booleano é imutável. Use "Boolean.valueOf (qualquer que seja)", que criará uma referência que aponta para Boolean.TRUE ou Boolean.False, dependendo do que for.
precisa saber é o seguinte
1
Um dos muitos problemas com Java (IMHO após 12 anos) é a inconsistência na abordagem de valores nulos que as linguagens antigas também possuem. Examinando o Scala, ele tem o conceito de uma opção digitada que pode ser nula ou pode ter um valor (subclasses Nenhuma ou Alguma). Em seguida, você pode chamar myOption.getOrElse (defaultValue). Consulte scala-lang.org/api/current/scala/Option.html, não há nada complexo sobre esse recurso. No entanto, como é incorporado à nova linguagem da JVM, muitas bibliotecas a usam. Isso faz com que a escala "conserte" parte da edição do "século passado" do Java, mas ainda compila os arquivos de classe que são executados no JRE.
simbo1905
10

As classes de wrapper para primitivas podem ser usadas onde os objetos são necessários, as coleções são uma boa amostra.

Imagine que você precisa para alguma loja motivo uma sequência de booleanem uma ArrayList, isso pode ser feito por boxe booleanna Boolean.

Há algumas palavras sobre isso aqui

Da documentação:

Como qualquer programador Java sabe, você não pode colocar um int (ou outro valor primitivo) em uma coleção. As coleções podem conter apenas referências de objetos, portanto, você deve colocar valores primitivos na classe de wrapper apropriada (que é Inteiro no caso de int). Quando você tira o objeto da coleção, obtém o número inteiro inserido; se você precisar de um int, desmarque o número inteiro usando o método intValue. Todo esse boxe e unboxing é uma dor, e desorganiza seu código. O recurso autoboxing e unboxing automatiza o processo, eliminando a dor e a confusão.

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

Francisco Spaeth
fonte
3

BooleanO wrapper é útil quando você deseja se o valor foi atribuído ou não, além de truee false. Possui os seguintes três estados:

  • Verdade
  • Falso
  • Não definido qual é null

Considerando que booleanpossui apenas dois estados:

  • Verdade
  • Falso

A diferença acima o tornará útil nas Listas de Booleanvalores, que podem ter True, Falseou Null.

Ramesh PVK
fonte
Não, ele não tem um estado nulo, essa é a referência.
Matsemann
O que eu quis dizer foi Bolean pode ser usado para definido como True / False e Not Defined.
Ramesh PVK
3

Suponho que, em alguns casos, você deva ter um mecanismo para distinguir um campo booleano que já defina valor ou não.

Thinhbk
fonte
1

O objetivo principal do booleano é o valor nulo. O valor nulo diz que essa propriedade é indefinida , por exemplo, na coluna anulável do banco de dados.

Se você realmente precisar converter tudo de booleano primitivo em booleano de wrapper, poderá usar o seguinte para dar suporte ao código antigo:

Boolean set = Boolean.FALSE; //set to default value primitive value (false)
...
if (set) ...
JMelnik
fonte
6
'O objetivo principal é o valor nulo'. Não, o principal objetivo do booleano é passar uma referência a um booleano como objeto.
user606723
@ user606723 concordou, eu estava me referindo ao caso do banco de dados enquanto estava escrevendo.
JMelnik
1

Existem muitos usos para o valor ** null ** no wrapper booleano! :)

Por exemplo, você pode ter em um formulário um campo chamado "boletim informativo" que indica se o usuário deseja ou não um boletim informativo em seu site. Se o usuário não selecionar um valor nesse campo, convém implementar um comportamento padrão para essa situação (enviar? Não enviar ?, questionar novamente ?, etc). Claramente, não definido (ou não selecionado ou ** nulo **), não é o mesmo que verdadeiro ou falso.

Mas, se "não definido" não se aplicar ao seu modelo, não altere a primitiva booleana;)

dcasanueva
fonte
1

Em uma definição estrita de um elemento booleano, existem apenas dois valores. Em um mundo perfeito, isso seria verdade. No mundo real, o elemento pode estar ausente ou desconhecido. Normalmente, isso envolve a entrada do usuário. Em um sistema baseado em tela, ele pode ser forçado por uma edição. Em um mundo em lotes usando um banco de dados ou entrada XML, o elemento pode estar facilmente ausente.

Portanto, no mundo não perfeito em que vivemos, o objeto booleano é ótimo, pois pode representar o estado ausente ou desconhecido como nulo. Afinal, os computadores apenas modelam o mundo real e devem dar conta de todos os estados possíveis e lidar com eles com exceções lançadas (principalmente porque existem casos de uso em que lançar a exceção seria a resposta correta).

No meu caso, o objeto booleano era a resposta perfeita, já que o XML de entrada às vezes tinha o elemento ausente e eu ainda podia obter um valor, atribuí-lo a um booleano e depois procurar um nulo antes de tentar usar um teste verdadeiro ou falso. .

Apenas meus 2 centavos.

user3228876
fonte
1

Para todas as boas respostas acima, vou apenas dar um exemplo concreto no servlet Java HttpSession classe de . Espero que este exemplo ajude a esclarecer alguma dúvida que você ainda possa ter.

Se você precisar armazenar e recuperar valores para uma sessão, use o método setAttribute(String, Object) e getAttribute(String, Object). Portanto, para um valor booleano, você é forçado a usar a classe booleana se desejar armazená-la em uma sessão http.

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

A última linha causará a NullPointerExceptionse os valores do atributo não estiverem definidos. (essa foi a razão que me levou a este post). Portanto, o estado lógico 3 chegou para ficar, se você prefere usá-lo ou não.

Wacker
fonte
0

A melhor maneira seria evitar completamente os booleanos, pois todo booleano implica que você tem uma declaração condicional em qualquer outro lugar do seu código (consulte http://www.antiifcampaign.com/ e esta pergunta: Você pode escrever qualquer algoritmo sem uma declaração if ? ).

No entanto, pragmaticamente você precisa usar booleanos de tempos em tempos, mas, como você já descobriu por si mesmo, lidar com booleanos é mais suscetível a erros e mais complicado. Então, eu sugiro usar booleanos sempre que possível. Exceções disso podem ser um banco de dados legado com colunas booleanas anuláveis, embora eu tentasse ocultar isso também no meu mapeamento.

Roland Schneider
fonte
Lidar com booleanos é tão propenso a erros quanto lidar com qualquer outro objeto. BTW, o link é contra a proliferação de IFs para verificação de tipo, não para uso geral. E, por sua vez, isso é "perigoso" porque torna as modificações mais difíceis. Portanto, não há nada errado com os IFs em si.
Sr. Smith
Não é uma resposta para a pergunta.
Matsemann
@MisterSmith Quando um sinalizador booleano é frequentemente usado como uma variável de verificação de tipo, o link também pode ser aplicado aqui. Deve ser apenas uma dica de que se deve pensar se um booleano é a ferramenta certa em uma determinada situação. A afirmação "evitar completamente os booleanos" é obviamente muito radical e praticamente impossível, e foi por isso que adicionei o segundo parágrafo. Também adicionei um "mais propenso a erros e mais complicado" para esclarecer as coisas.
Roland Schneider
0

Booleano pode ser muito útil quando você precisa de três estados. Como no teste de software, se o teste for aprovado, envie true, se falhar, envie false e se o caso de teste for interrompido, envie null, o que indicará que o caso de teste não foi executado.

Aamir
fonte
2
As enums não seriam melhores para isso? Ao contrário de possivelmente rendendo NullPointerExceptions inesperados para um cliente, enums iria definir explicitamente "estados"
Kartik Chugh
Sempre prefira enums em vez de booleanos em máquinas de estado. Você nunca sabe quando um novo quarto estado chega no requisito comercial.
AnupamChugh