检查空布尔值为真是否会导致异常

237

我有以下代码:

Boolean bool = null;

try 
{
    if (bool)
    {
        //DoSomething
    }                   
} 
catch (Exception e) 
{
    System.out.println(e.getMessage());             
}
为什么对布尔变量“bool”进行检查会导致异常?它不应该在“看到”它不为真时直接跳过if语句吗? 当我删除if语句或检查它是否不为空时,异常会消失。

4
关于对象拆箱的上面的回答都是正确的。然而,为了完整起见,您还可以将代码更改为使用基本类型"boolean"而不是对象包装器"Boolean"。您还应该了解一下原始类型和对象之间的区别。 - Marvo
同时,如果 if (bool == Boolean.TRUE) 在不生成异常的情况下评估为 false。我不确定这是否是我刚刚发现的意图。 - simon.watts
4
如果boolnull或者Boolean被显式构造(而不是作为对Boolean.TRUE的引用),那么bool == true的结论是错误的。因此不建议使用此方法,建议使用if (Boolean.TRUE.equals(bool))来实现预期的结果,包括安全地处理null值。 - StaxMan
8个回答

572

如果您不喜欢额外的空值检查:

if (Boolean.TRUE.equals(value)) {...}

2
@AvrDragon:需要使用equals吗?由于布尔类型只有两个值,因此可以在这里使用运算符==。 - Atul
13
是的,这里需要使用“equals”。因为(new Boolean(true) == new Boolean(true))的结果是false。原因是:Boolean只是一个类,在Java中可以像其他类一样有多个实例。 - AvrDragon
51
是的,这很遗憾,构造函数应该是私有的,以确保它是一个双例模式... - fortran
5
иҝҷжӯЈжҳҜApache BooleanUtilsзҡ„BooleanUtils.isTrue(bool)жүҖеҒҡзҡ„дәӢжғ…гҖӮ - nidheeshdas
16
使用Apache BooleanUtils 毫无意义,这个习惯用法已经很好了。 - StaxMan
显示剩余2条评论

206

当你有一个 boolean 时,它只能是 true 或者 false。但是当你有一个 Boolean 时,它可以是任何对象一样的 Boolean.TRUEBoolean.FALSE 或者 null

在你的特定情况下,你的 Booleannull,而 if 语句会触发隐式转换成 boolean,从而产生了 NullPointerException。你可能需要使用:

if(bool != null && bool) { ... }

25
从技术上讲,“Boolean”可以是任意数量的“true”实例,不仅仅是“Boolean.TRUE”。例如,“new Boolean(true)”。 - Steve Kuo
6
我很难理解为什么 if (myBoolean)(其中myBoolean是一个Boolean类型的变量)不会引发编译错误,至少也应该有一个警告。这肯定是一个“坑点”。 - Josh M.
4
@JoshM。这是因为Java进行包装类的装箱(Boxing)和拆箱(Unboxing):https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html - Vinicius
8
@Vinicius 确实,但在这种情况下,编译器应该为我们执行null操作,或者至少发出编译器警告。 - Josh M.
Android Studio 不接受 'bool != null'。 - صلي علي محمد - Atef Farouk

110

使用Apache BooleanUtils

(如果在您的项目中,性能是最重要的考虑因素,请查看其他答案,其中包含不需要包含外部库的本地解决方案。)

不要重复造轮子。利用已经构建的内容,并使用isTrue()

BooleanUtils.isTrue( bool );

检查一个Boolean值是否为真,如果传入值为null则返回false

如果您不受到“允许”使用的库的限制,则有许多用于各种用例(包括BooleansStrings)的优秀辅助函数。我建议您浏览各种Apache库并看看它们已经提供了什么。


86
当所需的基本功能如此之简单时,使用外部库似乎不如重新发明轮子。 - Paul Manta
5
我同意如果这是您在Apache Utils库中唯一使用的功能,但建议的想法是“浏览”库以暴露自己于其他有用的函数。 - Joshua Pinter
9
那个库正在重新发明轮子。我尽可能避免使用这样的库。 - Martín Schonaker
7
如果Apache BooleanUtils在重复造轮子,那么最初的轮子是什么?目的是避免创建一堆辅助函数,这些函数模仿已经在类似于这样的库中完成的工作。我还在我的所有应用程序中使用该库的toStringYesNo函数。 - Joshua Pinter
3
原始代码中的轮子不是Boolean.TRUE.equals(bool)吗?BooleanUtils中确实有一些有用的方法,但这并不是必需的。 - nnnnnn
显示剩余8条评论

38

或者使用Java 8的Optional功能,你也可以执行这样的技巧:

Optional.ofNullable(boolValue).orElse(false)

:)


5
这个答案应该得到更多的认可,但这只是我的观点。 - Roshan Upreti

18

Boolean类型可以为null。由于你已将其设置为null,所以需要进行null检查。

if (bool != null && bool)
{
  //DoSomething
}                   

2

if (bool) 会被编译成 if (bool.booleanValue()),也就是自动拆箱,如果 boolnull,则会抛出 NullPointerException

对于可空的包装类型 Boolean 的其他解决方案:

这里将false作为 null-case 的默认值。


1

由于您的变量 bool 指向 null,因此您将始终收到 NullPointerException,您需要在某个地方首先使用非 null 值初始化变量,然后再修改它。


2
如果只是这样,catch 块将处理 NullPointerException。问题在于 OP 尝试将 null 引用拆箱为原始类型。 - Mike Adler
1
“you will always” - 不总是,除了样例简化代码之外,在初始化变量为“null”并测试它之间不执行任何操作。假设真实代码不会那么简单,否则整个“if”测试可以被删除。 - nnnnnn

1

Objects.equals()

K-ballo 的答案没有任何问题。 如果您喜欢单个简单条件,并且像我一样不喜欢 Yoda 条件,那么自从 Java 1.7 以来,答案就是:

    if (Objects.equals(bool, true)) {

或者如果您同时更喜欢非常明确

    if (Objects.equals(bool, Boolean.TRUE)) {

或者更好的方法:避免这个问题

不建议使用Boolean对象,从而允许Boolean引用在第一次使用时为null。像你看到的那样,NullPointerException的风险太大了。如果需要一种三态逻辑,最好定义一个有三个值的枚举。例如:

enum MyTristateBoolean { FALSE, DONT_KNOW, TRUE }

现在我们根本不需要null了。中间的常量可能应该被命名为UNKNOWNUNDEFINEDNOT_EXISTING或者其他一些与你的具体情况相关的名称。如果合适的话,甚至可以将其命名为NULL。现在,根据个人喜好,你的比较会变成以下两种之一。

    if (myBool.equals(MyTristateBoolean.TRUE)) {

    if (myBool == MyTristateBoolean.TRUE) {

后者可行,因为编译器保证每个枚举常量只有一个实例。正如大多数人所知,==不能用于比较非枚举类型的对象是否相等。


我强烈推荐这个答案。这是一个很棒的答案,遵循了最佳实践。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接