什么时候应该使用布尔值的空值?


159

Java的boolean允许值true,并false同时允许布尔值truefalsenull。我已经开始将booleans 转换为Booleans。这可能会导致测试崩溃,例如

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

而测试

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

似乎是人为的并且容易出错。

何时(如果有)将Booleans与空值一起使用是否有用?如果从不,那么包装对象的主要优点是什么?

更新:有很多有价值的答案,我在自己的答案中总结了其中一些。我充其量只是Java的中级课程,因此我尝试展示了一些我认为有用的东西。请注意,问题是“用词不正确”(布尔值不能“具有空值”),但如果其他人有相同的误解,我将其保留


7
有时,您需要一个未初始化的状态,并设置Boolean变量以提供null帮助。
nhahtdh 2012年

2
我不敢确认“ Always”有点强,但是我希望测试null一下它是否真的用作第三状态。
nhahtdh 2012年

6
您是否有理由将布尔值转换为布尔值?我会坚持使用原始类型,并且仅在有充分理由这样做时才将其包装,例如,当我需要通过引用传递变量时。
jpe 2012年


6
没有“ 布尔值的空值”之类的东西。A Boolean是对象,而a boolean是“标量”。如果Boolean引用设置为null,则意味着相应的Boolean对象不存在。您不能在不存在的东西中放置任何东西。
Hot Licks 2012年

Answers:


244

使用boolean而不是Boolean每次都可以。这样可以避免很多NullPointerException,并使您的代码更健壮。

Boolean 很有用,例如

  • 将布尔值存储在集合中(列表,地图等)
  • 表示可为空的布尔值(例如,来自数据库中的可为空的布尔值列)。在这种情况下,null值可能表示“我们不知道它是对还是错”。
  • 每次方法需要一个Object作为参数,并且您需要传递一个布尔值。例如,当使用反射或类似的方法时MessageFormat.format()

35
数据库中的空值也可能意味着“ FileNotFound”
Karl Johan 2012年

31
我认为,第二点确实是对这个问题正确答案的核心。
Niels Brinch 2012年

3
我曾经拥有的布尔型的另一种用法是在扩展泛型类时作为泛型类型参数-与第3点密切相关
Alex

6
用“ Universe不知道”以外的含义重载null概念比使用3(或更多)值的枚举要弱。使将参数传递给方法的代码的读取也更加明确。
bluevector 2012年

16
或#4 :(Boolean isSchrodinger‎CatAlive = null;对不起,无法抗拒;))。
Matthieu 2013年

58

我几乎从不使用Boolean它,因为它的语义含糊不清。基本上,您具有三态逻辑:对,错或未知。有时,当您在两个值之间进行选择,而用户根本不回答,并且您确实想知道该信息时,使用它很有用(请考虑:可空数据库列)。

我认为没有理由将其转换为booleanBoolean因为它会带来额外的内存开销,NPE可能性和更少的键入。通常我会用尴尬BooleanUtils.isTrue()来使我的生活轻松一些Boolean

存在的唯一原因Boolean是具有Boolean类型集合的能力(泛型boolean以及所有其他原语都不允许)。


1
不过,它是一个外部库(Apache Commons)。
nhahtdh 2012年

4
对于多值逻辑,最好使用枚举。因此,应为(自动)装箱变量保留布尔值,以用于数据结构。
jpe 2012年

39
使用Boolean时,避免空指针异常的便捷测试是Boolean.TRUE.equals(myBooleanObject)Boolean.FALSE.equals(myBooleanObject)
Christopher Peisert 2012年

10
布尔对象只有两个状态- truefalsenull不是所述对象的状态,而是对象引用的状态。
Hot Licks 2012年

2
让apache isTrue()公用程序变得像“有人可能会加重计算布尔值...让我们做一个方法...”听起来像是效用函数历史上最愚蠢的事情。但是,无论如何,它很有用……这是这里最大的wtf。
corsiKa 2012年

33

哇,到底是什么?仅仅是我还是所有这些答案都是错误的,或者至少是误导性的?

布尔类是布尔基本类型的包装。使用此包装器的目的是能够在接受对象或泛型的方法中传递布尔值。即向量。

布尔对象永远不能具有null值。如果您布尔值的引用为null,则仅表示从未创建布尔值。

您可能会发现这很有用:http : //grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Boolean.java

空布尔引用应仅用于触发具有其他空引用的类似逻辑。将其用于三种状态逻辑很笨拙。

编辑:注意,这Boolean a = true;是一个误导性陈述。这实际上等于更接近。Boolean a = new Boolean(true); 请在此处查看自动装箱:http : //en.wikipedia.org/wiki/Boxing_%28computer_science%29#Autoboxing

也许这就是很多困惑的来源。

EDIT2:请阅读下面的评论。如果有人对如何重组我的答案以纳入此构想有想法,请这样做。


2
我不理解您的陈述“布尔值永远不能具有null值”。我可以创建一个布尔值(Boolean a = true;),然后将a设置为null(a = null;)。它可能不是优雅或明智的,但有可能。
peter.murray.rust 2012年

7
当你做的时候Boolean a; a是指向布尔对象的指针。如果您a = null;尚未将布尔值设置为null,则将引用设置为null。难道Boolean a = null; a.booleanValue();在这种情况下,你甚至从来没有创建一个Boolean对象,因此它会抛出NullPointerException。让我知道您是否需要进一步的指导。
user606723 2012年

此外,当您执行时Boolean a = true;,它会执行某种魔术,实际上Boolean a = new Boolean(true);由于性能原因,它们可能无法完全正确地解释为Thats,但是您必须意识到Boolean仍然是一个对象。
user606723 2012年

7
@missingno,处理任何对象的所有代码都必须处理这个问题。对象引用可以为null或不为null。这不是特殊情况,不需要特殊考虑。
user606723 2012年

3
你错过了我的观点@missingno。我同意我们需要考虑空参考值。我从来没有反对过那个。但是我们需要针对任何对象引用进行此操作空布尔引用不是特殊情况。因此,空布尔参考值不需要特殊考虑。
user606723 2012年

24

有三个快速原因:

  • 来表示数据库布尔值,其可以是truefalsenull
  • 表示xsd:boolean用声明的XML Schema的值xsd:nillable="true"
  • 能够使用通用类型:List<Boolean>-您不能使用List<boolean>

我已经明确地写了“ boolean”,而不是“ boolean”(思维风格),因为在Oracle中,您通常使用char(1) null'T'和'F'值。因此,它可能(例如使用Hibernate类型适配器)为null :)
Grzegorz Grzybek,2012年

2
哪个数据库不允许布尔值为null?如果将列设置为可空,则数据类型不再重要...
Michal B.

@MichalB。Sybase(和SQL Server)位类型infocenter.sybase.com/help/index.jsp?topic=/…–
mmmmmm

@Mark-否,SQL Server确实允许可为空的位-msdn.microsoft.com/zh-cn/library/ms177603.aspx
David M

11

回答自己的问题:我认为回答我自己的问题会很有用,因为我从答案中学到了很多东西。该答案旨在帮助像我这样的人-对这些问题没有完全的了解。如果我使用不正确的语言,请纠正我。

  • 空“值”是不是值,是从根本上不同的truefalse。缺少对象的指针。因此,认为布尔值是三值是根本错误的
  • 布尔值的语法缩写,它隐藏了引用指向对象的事实:

    Boolean a = true;

隐藏了true作为对象的事实。其他等效分配可能是:

Boolean a = Boolean.TRUE;

要么

Boolean a = new Boolean(true);
  • 缩写语法

    if (a) ...

与大多数其他分配不同,并且掩盖了a可能是对象引用或图元的事实。如果是物体,则必须进行测试null以避免NPE。对我来说,如果进行平等测试,从心理上更容易记住这一点:

if (a == true) ...

可能会提示我们测试null。因此,简化形式只有在a是原始形式时才是安全的。

对于我自己,我现在有以下建议:

  • 切勿对3值逻辑使用null。只使用对与错。
  • 永远不要Boolean从方法返回null。只返回boolean
  • Boolean用于将元素包装在容器中,或用于需要对象的方法的参数

5
不要使用“新布尔值(无论如何)”。这将在堆上实例化一个新的布尔值。然而布尔是不可变的。使用“ Boolean.valueOf(whatever)”将创建一个引用,该引用指向Boolean.TRUE或Boolean.False,具体取决于什么。
simbo1905

1
Java的许多问题(12年后的恕我直言)是旧语言也存在的对空值的处理方式不一致的问题。看一下Scala,它具有类型化Option的概念,它可以为null或可以具有值(子类None或Some)。然后,您可以调用myOption.getOrElse(defaultValue)。请参阅scala-lang.org/api/current/scala/Option.html,此功能没有什么复杂的。然而,由于它是新JVM语言中内置的,所以许多库都在使用它。这使得规模“修复”了Java的“上个世纪”问题,但是它仍然可以编译为在JRE上运行的类文件。
simbo1905

10

原始对象的包装器类可以用于需要对象的地方,集合是一个很好的示例。

想象一下,你需要某种原因商店的序列boolean中的ArrayList,这可以通过拳击来完成booleanBoolean

有关于这几句话在这里

从文档:

正如任何Java程序员所知道的那样,您不能将int(或其他原始值)放入集合中。集合只能保存对象引用,因此您必须将原始值装箱到适当的包装器类中(在int情况下为Integer)。当您从集合中取出对象时,您将得到放入的Integer。如果需要一个int,则必须使用intValue方法将Integer拆箱。所有这些装箱和拆箱都很麻烦,并且会使您的代码混乱。自动装箱和拆箱功能可自动执行该过程,消除了痛苦和混乱。

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


3

Boolean当你想值是否是从分配或没有拆开包装是非常有用的truefalse。它具有以下三种状态:

  • 真正
  • 未定义哪个是 null

boolean只有两个状态:

  • 真正

上述差异将使其在名单有帮助的Boolean值,它可以有TrueFalseNull


不,它没有null状态,这就是参考。
Matsemann 2012年

我的意思是Bolean可以用于定义True / False和Not Defined。
拉梅什PVK 2012年

3

我想在某些情况下,您应该具有一种机制来区分是否已设置值的布尔字段。


1

布尔值的主要用途是空值。空值表示该属性未定义,例如以数据库可为空的列。

如果您确实需要将所有内容从原始布尔值转换为包装布尔值,那么可以使用以下代码来支持旧代码:

Boolean set = Boolean.FALSE; //set to default value primitive value (false)
...
if (set) ...

6
“主要目的是空值”。不,布尔值的主要目的是将对布尔值的引用作为对象传递。
user606723 2012年

@ user606723同意,我在写作时在脑海中指的是数据库案例。
JMelnik 2012年

1

布尔包装中的** null **值有很多用途!:)

例如,您可能具有一个名为“ newsletter”的字段,该字段指示用户是否要从您的站点获取新闻通讯。如果用户未在此字段中选择值,则可能要针对这种情况实施默认行为(发送?不发送?,再次询问?等)。显然,未设置(或未选择或“空”)与true或false不同。

但是,如果“ not set”不适用于您的模型,请不要更改布尔基元;)


1

在布尔元素的严格定义中,只有两个值。在一个完美的世界中,这是正确的。在现实世界中,元素可能丢失或未知。通常,这涉及用户输入。在基于屏幕的系统中,可以通过编辑来强制执行。在使用数据库或XML输入的批处理环境中,该元素很容易丢失。

因此,在我们生活的非完美世界中,布尔对象很棒,因为它可以将缺失或未知状态表示为null。毕竟,计算机只是对现实世界建模,应该考虑所有可能的状态并使用抛出异常来处理它们(主要是因为在某些用例中,抛出异常将是正确的响应)。

在我的情况下,布尔对象是一个完美的答案,因为输入XML有时缺少元素,我仍然可以获取一个值,将其分配给布尔值,然后在尝试使用真或假测试之前检查是否为null 。

只是我的2美分。


1

对于以上所有好的答案,我将在Java servlet HttpSession类中给出一个具体示例。希望该示例有助于阐明您可能仍有的一些问题。

如果需要存储和检索会话的值,请使用setAttribute(String,Object)和getAttribute(String,Object)方法。因此,对于布尔值,如果要将其存储在http会话中,则必须使用布尔类。

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

NullPointerException如果未设置属性值,则最后一行将导致。(这就是将我引导至此职位的原因)。因此,无论您是否愿意使用它,3逻辑状态都将保留下来。


0

最好的方法是完全避免使用布尔值,因为每个布尔值都意味着您在代码中的其他任何地方都有条件语句(请参阅http://www.antiifcampaign.com/和以下问题:您可以在没有if语句的情况下编写任何算法吗? ?)。

但是,务实的是,您必须不时使用布尔值,但是,正如您自己已经发现的那样,处理布尔值更容易出错且更麻烦。因此,我建议尽可能使用布尔值。例外情况可能是具有可空布尔值列的旧式数据库,尽管我也会尝试将其隐藏在映射中。


处理布尔值与处理任何其他对象一样容易出错。顺便说一句,该链接反对用于类型检查而非一般用途的IF的泛滥。反过来,这是“危险的”,因为它会使修改变得更加困难。因此,IF本身没有错。
史密斯先生2012年

不是这个问题的答案。
Matsemann 2012年

@MisterSmith Imho布尔标志经常被误用作类型检查变量,因此该链接也可以在此处应用。这只是一个提示,应该考虑在特定情况下布尔是否是正确的工具。当然,“完全避免布尔值”是非常激进的,几乎是不可能的,这就是为什么我添加第二段。我还添加了一个“更容易出错和更麻烦”的方式来澄清问题。
罗兰·施耐德

0

当您需要三种状态时,布尔值会非常有用。就像在软件测试中一样,如果通过测试,则发送true;如果失败,则发送false;如果测试用例被中断,则发送null,这表示未执行测试用例。


2
枚举不是最好的吗?与可能为客户端产生意外的NullPointerExceptions相反,枚举将显式定义“状态”
Kartik Chugh

在状态机中,总是喜欢枚举而不是布尔值。您永远不知道什么时候会出现新的第四状态。
AnupamChugh
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.