¿Cuándo deben usarse los valores nulos de booleano?

159

Java booleanpermite que los valores de truey falsemientras booleana permite true, falsey null. He comenzado a convertir mi booleans a Booleans. Esto puede causar bloqueos en pruebas como

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

mientras la prueba

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

Parece artificial y propenso a errores.

¿Cuándo, si alguna vez, es útil usar Booleans con valores nulos? Si nunca, ¿cuáles son las principales ventajas del objeto envuelto?

ACTUALIZACIÓN: Ha habido tantas respuestas valiosas que he resumido algunas de ellas en mi propia respuesta. En el mejor de los casos, soy un intermediario en Java, así que he intentado mostrar las cosas que encuentro útiles. Tenga en cuenta que la pregunta está "redactada incorrectamente" (el booleano no puede "tener un valor nulo") pero lo he dejado en caso de que otros tengan el mismo concepto erróneo

peter.murray.rust
fuente
77
A veces, desea un estado no inicializado y establecer Booleanvariables para nullayudar.
nhahtdh
3
"Siempre" es un poco fuerte que no me atrevo a confirmar, pero esperaría una prueba nullsi realmente se usa como un tercer estado.
nhahtdh
66
¿Tiene alguna razón para convertir booleanos a booleanos? Me quedaría con el tipo primitivo y lo envolvería solo si hay una buena razón para hacerlo, por ejemplo, cuando necesito pasar una variable por referencia.
jpe
77
También puede consultar esto: thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
biziclop
66
No existe un "valor nulo en un booleano". A Booleanes un objeto, mientras que a booleanes un "escalar". Si una Booleanreferencia se establece en nulo, eso significa que el Booleanobjeto correspondiente no existe. No puedes colocar nada dentro de algo que no existe.
Hot Licks

Respuestas:

244

Use en booleanlugar de Booleancada vez que pueda. Esto evitará muchos NullPointerExceptionsy hará que su código sea más robusto.

Boolean es útil, por ejemplo

  • para almacenar booleanos en una colección (Lista, Mapa, etc.)
  • para representar un booleano anulable (proveniente de una columna booleana anulable en una base de datos, por ejemplo). El valor nulo podría significar "no sabemos si es verdadero o falso" en este contexto.
  • cada vez que un método necesita un Objeto como argumento, y necesita pasar un valor booleano. Por ejemplo, cuando se usa reflexión o métodos como MessageFormat.format().
JB Nizet
fuente
35
Un valor nulo en la base de datos también podría significar "FileNotFound"
Karl Johan
31
Creo que su segunda viñeta es realmente el núcleo de la respuesta correcta a esta pregunta.
Niels Brinch
3
Otro uso para Boolean que he tenido es como parámetro de tipo genérico al extender clases genéricas, estrechamente relacionado con el punto 3.
Alex
66
Sobrecargar el concepto de nulo con un significado que no sea "el universo no lo sabe" es más débil que usar una enumeración con valor 3 (o más). Hace que la lectura del código que pasa los parámetros al método sea más explícita también.
bluevector
16
O # 4: Boolean isSchrodinger‎CatAlive = null;(lo siento, no pude resistir;)).
Matthieu
58

Casi nunca uso Booleanporque su semántica es vaga y oscura. Básicamente tiene lógica de 3 estados: verdadero, falso o desconocido. A veces es útil usarlo cuando, por ejemplo, le dio al usuario una opción entre dos valores y el usuario no respondió en absoluto y realmente quiere saber esa información (piense: columna de base de datos NULLable).

No veo ninguna razón para convertir de booleana, Booleanya que introduce una sobrecarga de memoria adicional, posibilidad de NPE y menos tipeo. Normalmente uso torpe BooleanUtils.isTrue()para hacer mi vida un poco más fácil Boolean.

La única razón de su existencia Booleanes la capacidad de tener colecciones de Booleantipos (los genéricos no permiten boolean, así como todas las demás primitivas).

Tomasz Nurkiewicz
fuente
1
Sin embargo, es una biblioteca externa (comunes de Apache).
nhahtdh
44
Para la lógica multivalor es preferible usar enumeraciones. Por lo tanto, Boolean debe dejarse para las variables de boxeo (automático) para su uso en estructuras de datos.
jpe
39
Cuando se usa Boolean, una prueba conveniente para evitar excepciones de puntero nulo es Boolean.TRUE.equals(myBooleanObject)o Boolean.FALSE.equals(myBooleanObject).
Christopher Peisert
10
Un objeto booleano tiene solo dos estados, truey false. nonull es un estado del objeto, sino un estado de la referencia del objeto.
Hot Licks
2
Deja que apache commons sea como "Alguien podría arruinar la evaluación de booleanos ... hagamos un isTrue()método ..." que suena como la cosa más tonta en la historia de las funciones de utilidad. Y sin embargo, de alguna manera, es útil ... esa es la mayor wtf aquí.
corsiKa
33

Wow, que demonios? ¿Soy solo yo o todas estas respuestas son incorrectas o al menos engañosas?

La clase booleana es un contenedor alrededor del tipo primitivo booleano. El uso de este contenedor es para poder pasar un valor booleano en un método que acepte un objeto o genérico. Es decir, vector.

Un objeto booleano NUNCA puede tener un valor nulo. Si su referencia a un booleano es nula, simplemente significa que su booleano nunca fue creado.

Puede encontrar esto útil: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Boolean.java

Una referencia booleana nula solo debe usarse para activar una lógica similar a la que tiene cualquier otra referencia nula. Usarlo para la lógica de tres estados es torpe.

EDITAR: aviso, esa Boolean a = true;es una declaración engañosa. Esto realmente equivale a algo más cercano a Boolean a = new Boolean(true); Por favor vea autoboxing aquí: http://en.wikipedia.org/wiki/Boxing_%28computer_science%29#Autoboxing

Quizás de aquí proviene gran parte de la confusión.

EDIT2: Lea los comentarios a continuación. Si alguien tiene una idea de cómo reestructurar mi respuesta para incorporar esto, hágalo.

usuario606723
fuente
2
No entiendo su afirmación "Un booleano NUNCA puede tener un valor nulo". Puedo crear un Boolean ( Boolean a = true;) y luego establecer un a nulo ( a = null;). Puede que no sea elegante o sabio, pero es posible.
peter.murray.rust
77
Cuando lo hagas Boolean a; a es un puntero a un objeto booleano. Si no a = null;ha establecido su valor booleano en nulo, ha establecido su referencia en nulo. Hacer Boolean a = null; a.booleanValue();En este caso, ni siquiera se ha creado un objeto Boolean y por lo tanto se va a lanzar una NullPointerException. Avíseme si necesita más instrucciones.
user606723
Además, cuando lo haces Boolean a = true;, hace algún tipo de magia que en realidad se interpreta como Boolean a = new Boolean(true);Eso probablemente no sea completamente correcto por razones de rendimiento, pero debes darte cuenta de que el Booleano sigue siendo un objeto.
user606723
77
@missingno, todo el código que trata con cualquier objeto tiene que lidiar con esto. Una referencia de objeto puede ser nula o no. Este no es un caso especial y no requiere una consideración especial.
user606723
3
Te estás perdiendo mi punto @missingno. Estoy de acuerdo en que debemos considerar valores de referencia nulos. Nunca estuve discutiendo en contra de eso. Pero necesitamos hacer esto para CUALQUIER REFERENCIA DE OBJETO. Una referencia booleana nula no es un caso especial. Y, por lo tanto, los valores de referencia booleanos nulos no requieren una consideración especial.
user606723
24

Hay tres razones rápidas:

  • para representar valores booleanos de la base de datos, que pueden ser true, falseonull
  • para representar los xsd:booleanvalores del esquema XML declarados conxsd:nillable="true"
  • para poder usar tipos genéricos: List<Boolean>- no puedes usarList<boolean>
Grzegorz Grzybek
fuente
He escrito explícitamente "boolean", no " boolean" (estilo mental), porque en Oracle generalmente se usa char(1) nullcon valores 'T' y 'F'. Por lo tanto, puede (con, por ejemplo, el adaptador de tipo Hibernate) ser nulo :)
Grzegorz Grzybek
2
¿Qué base de datos no permite nulo para booleano? Si configura la columna para que sea anulable, el tipo de datos ya no importa ...
Michal B.
@MichalB. Sybase (y SQL Server) tipo de bit infocenter.sybase.com/help/index.jsp?topic=/…
mmmmmm
@ Mark - no, SQL Server permite un bit anulable - msdn.microsoft.com/en-us/library/ms177603.aspx
David M
11

RESPUESTA A LA PROPIA PREGUNTA: Pensé que sería útil responder a mi propia pregunta, ya que he aprendido mucho de las respuestas. Esta respuesta está destinada a ayudar a aquellos, como yo, que no tienen una comprensión completa de los problemas. Si uso un lenguaje incorrecto, corrígeme.

  • El "valor" nulo no es un valor y es fundamentalmente diferente de truey false. Es la ausencia de un puntero a los objetos. Por lo tanto, pensar que Boolean tiene 3 valores es fundamentalmente incorrecto
  • La sintaxis para Boolean se abrevia y oculta el hecho de que la referencia apunta a Objetos:

    Boolean a = true;

oculta el hecho de que truees un objeto. Otras tareas equivalentes pueden ser:

Boolean a = Boolean.TRUE;

o

Boolean a = new Boolean(true);
  • La sintaxis abreviada

    if (a) ...

es diferente de la mayoría de las otras asignaciones y oculta el hecho de que a podría ser una referencia de objeto o una primitiva. Si es un objeto, es necesario probarlo para nullevitar NPE. Para mí es psicológicamente más fácil recordar esto si hay una prueba de igualdad:

if (a == true) ...

donde se nos podría pedir que hagamos una prueba para nulo. Entonces, la forma abreviada solo es segura cuando aes primitiva.

Para mí ahora tengo las recomendaciones:

  • Nunca use nulo para una lógica de 3 valores. Solo use verdadero y falso.
  • NUNCA regrese Booleande un método como podría ser null. Solo regreso boolean.
  • Solo se usa Booleanpara envolver elementos en contenedores o argumentos para métodos donde se requieren objetos
peter.murray.rust
fuente
55
No utilice "nuevo booleano (lo que sea)". Eso creará una nueva instancia booleana en el montón. Sin embargo, el booleano es inmutable. Utilice "Boolean.valueOf (lo que sea)" que creará una referencia que apunta a Boolean.TRUE o Boolean.False dependiendo de lo que sea.
simbo1905 01 de
1
Uno de los muchos problemas con Java (en mi humilde opinión después de 12 años) es la inconsistencia del enfoque de los valores nulos que también tienen los lenguajes antiguos. Echando un vistazo a Scala, tiene el concepto de una Opción escrita que puede ser nula o puede tener un valor (subclases Ninguna o Algunas). Luego puede llamar a myOption.getOrElse (defaultValue). Consulte scala-lang.org/api/current/scala/Option.html . Esta característica no tiene nada de complejo. Sin embargo, como está integrado en el nuevo lenguaje JVM, muchas bibliotecas lo usan. Eso hace que la escala "arregle" algunos de los problemas de Java del "siglo pasado", pero aún se compila en archivos de clase que se ejecutan en el JRE.
simbo1905
10

Las clases de contenedor para primitivas se pueden usar donde se requieren objetos, las colecciones son una buena muestra.

Imagínese que usted necesita por alguna razón tienda de una secuencia de booleanen una ArrayList, esto se puede hacer por el boxeo booleanen Boolean.

Hay algunas palabras sobre esto aquí

De la documentación:

Como sabe cualquier programador de Java, no puede poner un int (u otro valor primitivo) en una colección. Las colecciones solo pueden contener referencias de objetos, por lo que debe encuadrar valores primitivos en la clase de contenedor apropiada (que es Integer en el caso de int). Cuando saca el objeto de la colección, obtiene el número entero que ingresa; Si necesita un int, debe desempaquetar el número entero utilizando el método intValue. Todo este boxeo y unboxing es una molestia, y abarrota tu código. La función de autoboxing y unboxing automatiza el proceso, eliminando el dolor y el desorden.

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

Francisco Spaeth
fuente
3

Booleanwrapper es útil cuando quiere saber si el valor fue asignado o no, aparte de truey false. Tiene los siguientes tres estados:

  • Cierto
  • Falso
  • No está definido cuál es null

Mientras que booleansolo tiene dos estados:

  • Cierto
  • Falso

La diferencia anterior lo hará útil en las Listas de Booleanvalores, que pueden tener True, Falseo Null.

Ramesh PVK
fuente
No, no tiene un estado nulo, esa es la referencia.
Matsemann
Lo que quise decir es que Bolean se puede usar para Verdadero / Falso definido y No Definido.
Ramesh PVK
3

Supongo que, en algún caso, debería tener un mecanismo para distinguir un campo booleano que ya haya establecido un valor o no.

Thinhbk
fuente
1

El propósito principal de Boolean es el valor nulo. El valor nulo dice que esa propiedad no está definida , por ejemplo, tome la columna anulable de la base de datos.

Si realmente necesita convertir todo de booleano primitivo a booleano de envoltura, puede usar lo siguiente para admitir código antiguo:

Boolean set = Boolean.FALSE; //set to default value primitive value (false)
...
if (set) ...
JMelnik
fuente
66
'El objetivo principal es el valor nulo'. No, el propósito principal de Boolean es pasar una referencia a un boolean como un objeto.
user606723
@ user606723 estuvo de acuerdo, me refería al caso de la base de datos en mi mente mientras escribía.
JMelnik
1

¡Hay muchos usos para el valor ** nulo ** en el contenedor booleano! :)

Por ejemplo, puede tener en un formulario un campo llamado "boletín informativo" que indica si el usuario desea o no un boletín informativo de su sitio. Si el usuario no selecciona un valor en este campo, es posible que desee implementar un comportamiento predeterminado para esa situación (¿enviar ?, ¿no enviar ?, ¿pregunta nuevamente ?, etc.). Claramente, no establecido (o no seleccionado o ** nulo **), no es lo mismo que verdadero o falso.

Pero, si "no establecido" no se aplica a su modelo, no cambie la primitiva booleana;)

dcasanueva
fuente
1

En una definición estricta de un elemento booleano, solo hay dos valores. En un mundo perfecto, eso sería cierto. En el mundo real, el elemento puede faltar o ser desconocido. Por lo general, esto implica la entrada del usuario. En un sistema basado en pantalla, podría ser forzado por una edición. En un mundo por lotes que utiliza una base de datos o una entrada XML, el elemento podría faltar fácilmente.

Entonces, en el mundo no perfecto en el que vivimos, el objeto booleano es excelente ya que puede representar el estado desconocido o perdido como nulo. Después de todo, las computadoras simplemente modelan el mundo real y deben tener en cuenta todos los estados posibles y manejarlos con excepciones de lanzamiento (principalmente porque hay casos de uso en los que lanzar la excepción sería la respuesta correcta).

En mi caso, el objeto booleano fue la respuesta perfecta ya que el XML de entrada a veces faltaba el elemento y todavía podía obtener un valor, asignarlo a un valor booleano y luego verificar un valor nulo antes de intentar usar una prueba verdadera o falsa con él .

Solo mis 2 centavos.

user3228876
fuente
1

Para todas las buenas respuestas anteriores, solo voy a dar un ejemplo concreto en la HttpSessionclase de servlet de Java . Espero que este ejemplo ayude a aclarar alguna pregunta que aún pueda tener.

Si necesita almacenar y recuperar valores para una sesión, utilice el método setAttribute(String, Object) y getAttribute(String, Object). Entonces, para un valor booleano, está obligado a usar la clase booleana si desea almacenarlo en una sesión http.

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

La última línea provocará un NullPointerExceptionsi los valores de los atributos no están establecidos. (que es la razón me llevó a esta publicación). Entonces, el estado lógico 3 está aquí para quedarse, ya sea que prefiera usarlo o no.

Wacker
fuente
0

La mejor manera sería booleanos evitar por completo, ya que cada booleano implica que usted tiene una sentencia condicional en cualquier otro lugar en el código (ver http://www.antiifcampaign.com/ y esta pregunta: ¿Se puede escribir cualquier algoritmo sin una sentencia if ? )

Sin embargo, pragmáticamente tiene que usar booleanos de vez en cuando, pero, como ya lo ha descubierto usted mismo, tratar con booleanos es más propenso a errores y más engorroso. Así que sugeriría usar booleanos siempre que sea posible. Las excepciones a esto podrían ser una base de datos heredada con columnas booleanas anulables, aunque también trataría de ocultar eso en mi mapeo.

Roland Schneider
fuente
Tratar con booleanos es tan propenso a errores como tratar con cualquier otro objeto. Por cierto, el enlace está en contra de la proliferación de IF para la verificación de tipo, no para uso general. Y a su vez, eso es "peligroso" porque dificulta las modificaciones. Por lo tanto, no hay nada malo con los IF per se.
Señor Smith
No es una respuesta a la pregunta.
Matsemann
@MisterSmith Imho, una bandera booleana a menudo se usa incorrectamente como una variable de verificación de tipo, por lo que el enlace también puede aplicarse aquí. Debería ser solo una pista de que uno debería pensar si un booleano es la herramienta adecuada en una determinada situación. La afirmación "evitar booleanos por completo" es, por supuesto, muy radical y prácticamente imposible, por eso agregué el segundo párrafo. También he agregado un "más propenso a errores y más engorroso" para aclarar las cosas.
Roland Schneider
0

Boolean puede ser muy útil cuando necesita tres estados. Al igual que en las pruebas de software, si se pasa la prueba, envíe verdadero, si falla, envíe falso y si el caso de prueba se interrumpe, envíe nulo, lo que indicará que el caso de prueba no se ejecutó.

Aamir
fuente
2
¿No serían las enumeraciones lo mejor para esto? A diferencia de la posibilidad de producir NullPointerExceptions inesperadas para un cliente, las enumeraciones definirían explícitamente "estados"
Kartik Chugh
Siempre prefiera enumeraciones en lugar de booleanos en máquinas de estado. Nunca se sabe cuándo llega un nuevo cuarto estado en el requisito comercial.
AnupamChugh