java - que - ¿Cuándo se deben usar valores nulos de Boolean?
comparar boolean java (14)
Java boolean
permite valores de true
y false
mientras que Boolean permite true
, false
y null
. Empecé a convertir mis boolean
a Boolean
. 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 Boolean
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 es "incorrectamente redactada" (Boolean no puede "tener un valor nulo") pero la dejé en caso de que otros tengan el mismo concepto erróneo.
¡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 indique si el usuario quiere o no desea 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 de nuevo ?, etc.). Claramente, no establecer (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;)
Boolean puede ser muy útil cuando necesita tres estados. Al igual que en las pruebas de software, si se pasa la prueba, se envía verdadero, si falla, se envía falso y si el caso de prueba se interrumpe, se envía nulo, lo que indicará que el caso de prueba no se ejecutó.
Casi nunca utilizo Boolean
porque su semántica es vaga y oscura. Básicamente tienes una lógica de 3 estados: verdadera, falsa o desconocida. 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 desea saber esa información (piense en la columna de la base de datos NULLable).
No veo ninguna razón para convertir de boolean
a Boolean
ya que introduce sobrecarga de memoria extra, posibilidad de NPE y menos tipeo. Normalmente utilizo BooleanUtils.isTrue()
incómodo para hacer mi vida un poco más fácil con Boolean
.
La única razón para la existencia de Boolean
es la capacidad de tener colecciones de tipo Boolean
(los genéricos no permiten boolean
, así como todas las demás primitivas).
El propósito principal de Boolean es el valor nulo. El valor nulo dice que esa propiedad no está definida , por ejemplo, tomar una columna nulable de la base de datos.
Si realmente necesita convertir todo desde booleano primitivo a wrapper booleano, entonces podría usar lo siguiente para soportar el código antiguo:
Boolean set = Boolean.FALSE; //set to default value primitive value (false)
...
if (set) ...
En una definición estricta de un elemento booleano, solo hay dos valores. En un mundo perfecto, eso sería verdad. En el mundo real, el elemento puede estar perdido o desconocido. Típicamente, esto involucra 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 perdido o desconocido 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 arrojadizas (sobre todo porque hay casos de uso donde arrojar la excepción sería la respuesta correcta).
En mi caso, el objeto booleano era la respuesta perfecta ya que el XML de entrada a veces tenía el elemento faltante y aún podía obtener un valor, asignarlo a un booleano y luego buscar un nulo antes de intentar usar una prueba verdadera o falsa con él .
Solo mis 2 centavos.
Hay tres razones rápidas:
- para representar los valores booleanos de la base de datos, que pueden ser
true
,false
onull
- para representar los valores
xsd:boolean
XML Schema declarados conxsd:nillable="true"
- para poder usar tipos genéricos:
List<Boolean>
- no puedes usarList<boolean>
La mejor manera sería evitar los booleanos por completo, ya que cada booleano implica que tiene una declaración condicional en cualquier otro lugar de su código (consulte http://www.antiifcampaign.com/ y esta pregunta: ¿Puede escribir cualquier algoritmo sin una instrucción if? ? ).
Sin embargo, pragmáticamente tiene que usar booleanos de vez en cuando, pero, como ya ha descubierto, lidiar con Booleanos es más propenso a errores y más engorroso. Entonces sugeriría usar booleanos siempre que sea posible. Las excepciones de esto podrían ser una base de datos heredada con columnas booleanas nullable, aunque también trataría de ocultar eso en mi mapeo.
Las clases de envoltura para primitivos se pueden usar donde se requieren objetos, las colecciones son una buena muestra.
Imagine que necesita por alguna razón almacenar una secuencia de boolean
en una ArrayList
, esto se puede hacer boxing boolean
en Boolean
.
Aquí hay algunas palabras sobre esto
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 a objetos, por lo que debe insertar valores primitivos en la clase contenedora apropiada (que es Integer en el caso de int). Cuando quitas el objeto de la colección, obtienes el entero que ingresas; si necesita un int, debe desagrupar el entero utilizando el método intValue. Todo este boxeo y unboxing es un dolor, y desordena su código. La característica 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
Para todas las buenas respuestas anteriores, voy a dar un ejemplo concreto en Java servlet clase HttpSession
. Espero que este ejemplo ayude a aclarar algunas preguntas que aún puede tener.
Si necesita almacenar y recuperar valores para una sesión, use los setAttribute
(String, Object) y getAttribute
(String, Object). Por lo tanto, para un valor booleano, se le obliga a usar la clase booleana si desea almacenarla en una sesión http.
HttpSession sess = request.getSession(false);
Boolean isAdmin = (Boolean) sess.getAttribute("admin");
if (! isAdmin) ...
La última línea causará una NullPointerException
si los valores de los atributos no están configurados. (que es la razón me llevó a esta publicación). Entonces el 3 estado lógico está aquí para quedarse, ya sea que prefiera usarlo o no.
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 utilizo un lenguaje incorrecto, corrígeme.
- El "valor" nulo no es un valor y es fundamentalmente diferente de
true
yfalse
. Es la ausencia de un puntero a los objetos. Por lo tanto, pensar que Boolean tiene 3 valores es fundamentalmente erróneo 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 true
es un objeto. Otras asignaciones 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 probar null
para evitar NPE. Para mí es psicológicamente más fácil recordar esto si hay una prueba de igualdad:
if (a == true) ...
donde se nos puede solicitar que pruebe null. Entonces, la forma abreviada solo es segura cuando a
es primitiva.
Para mí ahora tengo las recomendaciones:
- Nunca use null para una lógica de 3 valores. Solo usa verdadero y falso.
- NUNCA devuelva
Boolean
de un método ya que podría sernull
. Solo devuelveboolean
. - Use solo
Boolean
para envolver elementos en contenedores o argumentos para métodos donde se requieren objetos
Supongo que en algún caso, debe tener un mecanismo para distinguir un campo booleano que ya establece el valor o no.
Use boolean
lugar de Boolean
cada vez que pueda. Esto evitará muchos NullPointerException
y 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 valor booleano anulable (procedente 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, al usar reflexión o métodos como
MessageFormat.format()
.
Wow, ¿qué demonios? ¿Soy solo yo o todas estas respuestas son erróneas o al menos engañosas?
La clase booleana es un contenedor alrededor del tipo primitivo booleano. El uso de este envoltorio es para poder pasar un valor booleano en un método que acepta un objeto o genérico. Es decir, vector.
Un objeto booleano NUNCA puede tener un valor de nulo. Si su referencia a un booleano es nula, simplemente significa que su booleano nunca se creó.
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 desencadenar una lógica similar a la que tiene cualquier otra referencia nula. Usarlo para la lógica de tres estados es torpe.
EDITAR: aviso, ese 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, consulte el autoboxing aquí: http://en.wikipedia.org/wiki/Boxing_%28computer_science%29#Autoboxing
Quizás aquí es de donde 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.
Boolean
wrapper es útil cuando se quiere saber si el valor fue asignado o no, aparte de true
y false
. Tiene los siguientes tres estados:
- Cierto
- Falso
- No definido que es
null
Mientras que boolean
tiene solo dos estados:
- Cierto
- Falso
La diferencia anterior lo hará útil en las listas de valores Boolean
, que pueden tener True
, False
o Null
.