Quand faut-il utiliser des valeurs nulles de booléen?

159

Java booleanpermet des valeurs de trueet falsetout Boolean permet true, falseet null. J'ai commencé à convertir mes booleans en Booleans. Cela peut provoquer des plantages dans des tests tels que

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

tandis que le test

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

semble artificiel et sujet aux erreurs.

Quand, le cas échéant, est-il utile d'utiliser Booleans avec des valeurs nulles? Si jamais, quels sont les principaux avantages de l'objet enveloppé?

MISE À JOUR: Il y a eu tellement de réponses précieuses que j'en ai résumé certaines dans ma propre réponse. Je suis au mieux un intermédiaire en Java donc j'ai essayé de montrer les choses que je trouve utiles. Notez que la question est "mal formulée" (le booléen ne peut pas "avoir une valeur nulle") mais je l'ai laissée au cas où d'autres auraient la même idée fausse

peter.murray.rust
la source
7
Parfois, vous voulez un état non initialisé et définir la Booleanvariable sur nullaide.
nhahtdh
3
"Always" est un peu fort que je n'ose pas confirmer, mais je m'attendrais à un test pour savoir nulls'il est vraiment utilisé comme 3e état.
nhahtdh
6
Avez-vous une raison de convertir des booléens en booléens? Je m'en tiendrai au type primitif et ne l'envelopperai que s'il y a une bonne raison de le faire, par exemple lorsque je dois passer une variable par référence.
jpe
7
Vous pouvez également consulter ceci: thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
biziclop
6
Il n'y a pas de "valeur nulle dans un booléen". A Booleanest un objet, tandis que a booleanest un "scalaire". Si une Booleanréférence est définie sur null, cela signifie que l' Booleanobjet correspondant n'existe pas. Vous ne pouvez rien placer dans quelque chose qui n'existe pas.
Hot Licks

Réponses:

244

Utilisez booleanplutôt que Booleanchaque fois que vous le pouvez. Cela évitera de nombreux NullPointerExceptions et rendra votre code plus robuste.

Boolean est utile, par exemple

  • pour stocker des booléens dans une collection (List, Map, etc.)
  • pour représenter un booléen nullable (provenant d'une colonne booléenne nullable dans une base de données, par exemple). La valeur nulle peut signifier "nous ne savons pas si c'est vrai ou faux" dans ce contexte.
  • chaque fois qu'une méthode a besoin d'un Object comme argument, et vous devez passer une valeur booléenne. Par exemple, lorsque vous utilisez la réflexion ou des méthodes comme MessageFormat.format().
JB Nizet
la source
35
Une valeur nulle dans la base de données pourrait également signifier "FileNotFound"
Karl Johan
31
Votre deuxième puce est vraiment au cœur de la bonne réponse à cette question, je pense.
Niels Brinch
3
Une autre utilisation de Boolean que j'ai eue est en tant que paramètre de type générique lors de l'extension de classes génériques - étroitement lié au point 3.
Alex
6
Surcharger le concept de null avec une signification autre que «l'univers ne sait pas», c'est plus faible que d'utiliser une énumération de 3 valeurs (ou plus). Rend également plus explicite la lecture du code passant des paramètres dans la méthode.
bluevector
16
Ou # 4: Boolean isSchrodinger‎CatAlive = null;(désolé, n'a pas pu résister;)).
Matthieu
58

Je ne l'utilise presque jamais Booleancar sa sémantique est vague et obscure. Fondamentalement, vous avez une logique à 3 états: vrai, faux ou inconnu. Parfois, il est utile de l'utiliser lorsque, par exemple, vous avez donné à l'utilisateur le choix entre deux valeurs et que l'utilisateur n'a pas du tout répondu et que vous voulez vraiment connaître cette information (pensez: colonne de base de données NULLable).

Je ne vois aucune raison de convertir de booleanen Booleancar cela introduit une surcharge de mémoire supplémentaire, une possibilité NPE et moins de frappe. En général, j'utilise maladroit BooleanUtils.isTrue()pour rendre ma vie un peu plus facile avec Boolean.

La seule raison de l'existence de Booleanest la possibilité d'avoir des collections de Booleantype (les génériques ne le permettent pas boolean, ainsi que toutes les autres primitives).

Tomasz Nurkiewicz
la source
1
C'est une bibliothèque externe (Apache commons), cependant.
nhahtdh
4
Pour une logique à plusieurs valeurs, il est préférable d'utiliser des énumérations. Ainsi, Boolean doit être laissé pour les variables (auto) boxing à utiliser dans les structures de données.
jpe
39
Lors de l'utilisation de Boolean, un test pratique pour éviter les exceptions de pointeur nul est Boolean.TRUE.equals(myBooleanObject)ou Boolean.FALSE.equals(myBooleanObject).
Christopher Peisert
10
Un objet booléen n'a que deux états - trueet false. nulln'est pas un état de l'objet, mais plutôt un état de la référence d'objet.
Hot Licks
2
Laissez à Apache commons se dire "Quelqu'un pourrait se tromper en évaluant des booléens ... faisons une isTrue()méthode ..." qui sonne comme la chose la plus stupide de l'histoire des fonctions utilitaires. Et pourtant, d'une manière ou d'une autre, c'est utile ... c'est le plus gros wtf ici.
corsiKa
33

Wow, que diable? Est-ce juste moi ou est-ce que toutes ces réponses sont fausses ou du moins trompeuses?

La classe Boolean est un wrapper autour du type primitif booléen. L'utilisation de ce wrapper est de pouvoir passer un booléen dans une méthode qui accepte un objet ou générique. Ie vecteur.

Un objet booléen ne peut JAMAIS avoir une valeur nulle. Si votre référence à un booléen est nulle, cela signifie simplement que votre booléen n'a jamais été créé.

Vous trouverez peut-être cela utile: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Boolean.java

Une référence booléenne nulle ne doit être utilisée que pour déclencher une logique similaire à laquelle vous avez une autre référence nulle. L'utiliser pour une logique à trois états est maladroit.

EDIT: remarquez, c'est Boolean a = true;une déclaration trompeuse. Cela équivaut vraiment à quelque chose de plus proche de Boolean a = new Boolean(true); S'il vous plaît voir autoboxing ici: http://en.wikipedia.org/wiki/Boxing_%28computer_science%29#Autoboxing

C'est peut-être de là que vient une grande partie de la confusion.

EDIT2: Veuillez lire les commentaires ci-dessous. Si quelqu'un a une idée de la façon de restructurer ma réponse pour l'intégrer, faites-le.

user606723
la source
2
Je ne comprends pas votre déclaration "Un booléen ne peut JAMAIS avoir une valeur nulle". Je peux créer un booléen ( Boolean a = true;) puis définir un sur null ( a = null;). Ce n'est peut-être ni élégant ni sage, mais c'est possible.
peter.murray.rust
7
Quand vous faites Boolean a; a est un pointeur vers un objet booléen. Si vous a = null;n'avez pas défini votre valeur booléenne sur null, vous avez défini votre référence sur null. Est - ce que Boolean a = null; a.booleanValue();dans ce cas, vous même jamais créé un objet Boolean et donc il va une NullPointerException. Faites-moi savoir si vous avez besoin d'instructions supplémentaires.
user606723
De plus, quand vous le faites Boolean a = true;, cela fait une sorte de magie qui est en fait interprétée comme ce Boolean a = new Boolean(true);n'est probablement pas complètement correct pour des raisons de performances, mais vous devez vous rendre compte que le booléen est toujours un objet.
user606723
7
@missingno, tout code traitant de n'importe quel objet doit gérer cela. Une référence d'objet peut être nulle ou non. Ce n'est pas un cas particulier et ne nécessite pas de considération particulière.
user606723
3
Vous manquez mon point @missingno. Je conviens que nous devons considérer des valeurs de référence nulles. Je ne me suis jamais opposé à ça. Mais nous devons le faire pour TOUTE RÉFÉRENCE D'OBJET. Une référence booléenne nulle n'est pas un cas particulier. Et par conséquent, les valeurs de référence booléennes nulles ne nécessitent pas de considération particulière.
user606723
24

Il y a trois raisons rapides:

  • pour représenter les valeurs booléennes de la base de données, qui peuvent être true, falseounull
  • pour représenter les xsd:booleanvaleurs de XML Schema déclarées avecxsd:nillable="true"
  • pour pouvoir utiliser des types génériques: List<Boolean>- vous ne pouvez pas utiliserList<boolean>
Grzegorz Grzybek
la source
J'ai explicitement écrit "booléen", pas " boolean" (style mental), car dans Oracle, vous l'utilisez généralement char(1) nullavec les valeurs 'T' et 'F'. Donc, il peut (avec par exemple, un adaptateur de type Hibernate) être nul :)
Grzegorz Grzybek
2
Quelle base de données n'autorise pas null pour booléen? Si vous définissez la colonne comme nullable, le type de données n'a plus d'importance ...
Michal B.
@MichalB. Type de bit Sybase (et SQL Server) infocenter.sybase.com/help/index.jsp?topic=/…
mmmmmm
@Mark - non, SQL Server autorise un bit Nullable - msdn.microsoft.com/en-us/library/ms177603.aspx
David M
11

RÉPONSE À LA PROPRE QUESTION: J'ai pensé qu'il serait utile de répondre à ma propre question car j'ai beaucoup appris des réponses. Cette réponse vise à aider ceux - comme moi - qui n'ont pas une compréhension complète des problèmes. Si j'utilise un langage incorrect, veuillez me corriger.

  • La "valeur" nulle n'est pas une valeur et est fondamentalement différente de trueet false. C'est l'absence de pointeur sur les objets. Par conséquent, penser que booléen a une valeur de 3 est fondamentalement faux
  • La syntaxe de Boolean est abrégée et masque le fait que la référence pointe vers Objects:

    Boolean a = true;

cache le fait que truec'est un objet. D'autres affectations équivalentes peuvent être:

Boolean a = Boolean.TRUE;

ou

Boolean a = new Boolean(true);
  • La syntaxe abrégée

    if (a) ...

est différent de la plupart des autres affectations et cache le fait que a pourrait être une référence d'objet ou une primitive. Si un objet, il est nécessaire de tester pour nulléviter NPE. Pour moi, il est psychologiquement plus facile de se souvenir de ceci s'il y a un test d'égalité:

if (a == true) ...

où nous pourrions être invités à tester null. Ainsi, la forme raccourcie n'est sûre que lorsqu'elle aest primitive.

Pour moi, j'ai maintenant les recommandations:

  • N'utilisez jamais null pour une logique à 3 valeurs. N'utilisez que vrai et faux.
  • NE JAMAIS revenir Booleand'une méthode telle qu'elle pourrait l'être null. Seulement revenir boolean.
  • Utiliser uniquement Booleanpour encapsuler des éléments dans des conteneurs ou des arguments vers des méthodes où des objets sont requis
peter.murray.rust
la source
5
N'utilisez pas "new Boolean (peu importe)". Cela instanciera un nouveau booléen sur le tas. Pourtant, Boolean est immuable. Utilisez "Boolean.valueOf (peu importe)" qui créera une référence qui pointe vers Boolean.TRUE ou Boolean.False selon ce que vous voulez.
simbo1905
1
L'un des nombreux problèmes avec Java (IMHO après 12 ans) est l'incohérence de l'approche des valeurs nulles que les anciennes langues ont également. En regardant Scala, il a le concept d'une option typée qui peut être nulle ou peut avoir une valeur (sous-classes None ou Some). Ensuite, vous pouvez appeler myOption.getOrElse (defaultValue). Voir scala-lang.org/api/current/scala/Option.html il n'y a rien de complexe à propos de cette fonctionnalité. Pourtant, comme il est intégré au nouveau langage JVM, de nombreuses bibliothèques l'utilisent. Cela permet à l'échelle de "corriger" une partie du problème du "siècle dernier" de Java, mais il compile toujours en fichiers de classe qui s'exécutent sur le JRE.
simbo1905
10

Les classes wrapper pour les primitives peuvent être utilisées là où des objets sont requis, les collections sont un bon exemple.

Imaginez que vous ayez besoin pour une raison quelconque de stocker une séquence de booleandans un ArrayList, cela peut être fait en boxant booleandansBoolean .

Il y a quelques mots à ce sujet ici

De la documentation:

Comme tout programmeur Java le sait, vous ne pouvez pas mettre un int (ou une autre valeur primitive) dans une collection. Les collections ne peuvent contenir que des références d'objet, vous devez donc placer les valeurs primitives dans la classe wrapper appropriée (qui est Integer dans le cas de int). Lorsque vous retirez l'objet de la collection, vous obtenez l'entier que vous avez mis; si vous avez besoin d'un int, vous devez déballer l'entier à l'aide de la méthode intValue. Toute cette boxe et déballage est pénible et encombre votre code. La fonction de boîte automatique et de déballage automatise le processus, éliminant la douleur et l'encombrement.

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

Francisco Spaeth
la source
3

Booleanwrapper est utile lorsque vous voulez savoir si la valeur a été attribuée ou non en dehors de trueet false. Il a les trois états suivants:

  • Vrai
  • Faux
  • Non défini qui est null

Alors qu'il booleann'a que deux états:

  • Vrai
  • Faux

La différence ci-dessus le rendra utile dans les listes de Booleanvaleurs, qui peuvent avoir True, Falseou Null.

Ramesh PVK
la source
Non, il n'a pas d'état nul, c'est la référence.
Matsemann
Ce que je voulais dire, c'est que Bolean peut être utilisé pour défini Vrai / Faux et Non défini.
Ramesh PVK
3

Je suppose que dans certains cas, vous devriez avoir un mécanisme pour distinguer un champ booléen qui a déjà défini une valeur ou non.

Thinhbk
la source
1

Le but principal de Boolean est la valeur nulle. La valeur nulle indique que cette propriété n'est pas définie , par exemple, prenez la colonne Nullable de la base de données.

Si vous avez vraiment besoin de convertir tout le booléen primitif en booléen wrapper, vous pouvez utiliser ce qui suit pour prendre en charge l'ancien code:

Boolean set = Boolean.FALSE; //set to default value primitive value (false)
...
if (set) ...
JMelnik
la source
6
«Le but principal est la valeur nulle». Non, le but principal de Boolean est de transmettre une référence à un booléen en tant qu'objet.
user606723
@ user606723 d'accord, je faisais référence au cas de la base de données dans mon esprit pendant que j'écrivais.
JMelnik
1

Il existe de nombreuses utilisations de la valeur ** null ** dans le wrapper booléen! :)

Par exemple, vous pouvez avoir dans un formulaire un champ nommé "newsletter" qui indique si l'utilisateur veut ou ne veut pas une newsletter de votre site. Si l'utilisateur ne sélectionne pas de valeur dans ce champ, vous souhaiterez peut-être implémenter un comportement par défaut dans cette situation (envoyer? Ne pas envoyer ?, question à nouveau ?, etc.). Clairement, non défini (ou non sélectionné ou ** nul **), n'est pas la même chose que vrai ou faux.

Mais, si "non défini" ne s'applique pas à votre modèle, ne changez pas la primitive booléenne;)

dcasanueva
la source
1

Dans une définition stricte d'un élément booléen, il n'y a que deux valeurs. Dans un monde parfait, ce serait vrai. Dans le monde réel, l'élément peut être manquant ou inconnu. En règle générale, cela implique une entrée de l'utilisateur. Dans un système basé sur un écran, il pourrait être forcé par une modification. Dans un monde par lots utilisant une base de données ou une entrée XML, l'élément peut facilement manquer.

Ainsi, dans le monde non parfait dans lequel nous vivons, l'objet booléen est génial en ce sens qu'il peut représenter l'état manquant ou inconnu comme nul. Après tout, les ordinateurs modélisent simplement le monde réel et doivent tenir compte de tous les états possibles et les gérer avec des exceptions (surtout parce qu'il existe des cas d'utilisation où lancer l'exception serait la bonne réponse).

Dans mon cas, l'objet booléen était la réponse parfaite car le XML d'entrée avait parfois l'élément manquant et je pouvais toujours obtenir une valeur, l'attribuer à un booléen puis vérifier la valeur null avant d'essayer d'utiliser un test vrai ou faux avec lui .

Juste mes 2 cents.

user3228876
la source
1

Pour toutes les bonnes réponses ci-dessus, je vais juste donner un exemple concret dans la HttpSessionclasse de servlet Java . J'espère que cet exemple vous aidera à clarifier une question que vous vous posez peut-être encore.

Si vous devez stocker et récupérer des valeurs pour une session, vous utilisez la méthode setAttribute(String, Object) et getAttribute(String, Object). Donc pour une valeur booléenne, vous êtes obligé d'utiliser la classe Boolean si vous souhaitez la stocker dans une session http.

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

La dernière ligne provoquera un NullPointerExceptionsi les valeurs d'attribut ne sont pas définies. (ce qui est la raison qui m'a conduit à ce post). L'état logique 3 est donc là pour rester, que vous préfériez l'utiliser ou non.

Wacker
la source
0

Le meilleur moyen serait d'éviter complètement les booléens, car chaque booléen implique que vous avez une instruction conditionnelle n'importe où ailleurs dans votre code (voir http://www.antiifcampaign.com/ et cette question: Pouvez-vous écrire un algorithme sans instruction if ? ).

Cependant, de manière pragmatique, vous devez utiliser des booléens de temps en temps, mais, comme vous l'avez déjà découvert par vous-même, gérer les booléens est plus sujet aux erreurs et plus fastidieux. Je suggérerais donc d'utiliser des booléens dans la mesure du possible. Les exceptions à cela pourraient être une base de données héritée avec des colonnes booléennes nullables, bien que j'essaierais de cacher cela également dans mon mappage.

Roland Schneider
la source
Le traitement des booléens est aussi sujet aux erreurs que celui de tout autre objet. BTW, le lien est contre la prolifération des IF pour la vérification de type, pas pour un usage général. Et en retour, c'est «dangereux» car cela rend les modifications plus difficiles. Il n'y a donc rien de mal avec les FI en soi.
Mister Smith
Pas une réponse à la question.
Matsemann
@MisterSmith Imho, un indicateur booléen est souvent utilisé à mauvais escient comme variable de vérification de type, le lien peut donc s'appliquer ici aussi. Cela devrait juste être une indication que l'on devrait se demander si un booléen est le bon outil dans une certaine situation. La déclaration «éviter complètement les booléens» est bien sûr très radicale et pratiquement impossible, c'est pourquoi j'ai ajouté le deuxième paragraphe. J'ai également ajouté un "plus sujet aux erreurs et plus encombrant" pour clarifier les choses.
Roland Schneider
0

Boolean peut être très utile lorsque vous avez besoin de trois états. Comme dans les tests logiciels, si le test est réussi, envoyez true, en cas d'échec, envoyez false et si le cas de test est interrompu, envoyez null, ce qui indiquera que le cas de test n'a pas été exécuté.

Aamir
la source
2
Les énumérations ne seraient-elles pas meilleures pour cela? Au lieu de produire des NullPointerExceptions inattendues pour un client, les énumérations définiraient explicitement les «états»
Kartik Chugh
Préférez toujours les énumérations au lieu des booléens dans les machines à états. Vous ne savez jamais quand un nouveau quatrième état arrive dans l'exigence métier.
AnupamChugh le