【问题标题】:Check if null Boolean is true results in exception检查 null Boolean 是否为真导致异常
【发布时间】:2012-06-15 20:16:06
【问题描述】:

我有以下代码:

Boolean bool = null;

try 
{
    if (bool)
    {
        //DoSomething
    }                   
} 
catch (Exception e) 
{
    System.out.println(e.getMessage());             
}

为什么我对布尔变量“bool”的检查会导致异常? 当它“看到”它不是真的时,它不应该直接跳过 if 语句吗? 当我删除 if 语句或检查它是否为空时,异常消失。

【问题讨论】:

  • 以上关于对象拆箱的答案都是正确的。但是,为了完整起见,您也可以更改代码以使用原始“布尔”而不是对象包装器“布尔”。您还应该重新了解基元和对象之间的区别。
  • 同时...if (bool == Boolean.TRUE) 评估为 false 而不产生异常。不确定在我刚刚发现的情况下这是否是故意的。
  • @simon.watts 如果boolnullBoolean 是显式构造的(而不是作为对Boolean.TRUE 的引用),这将是错误的。所以不推荐;与 if (Boolean.TRUE.equals(bool)) 不同,后者将按预期工作,包括安全处理 null 值。

标签: java


【解决方案1】:

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

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

【讨论】:

  • @AvrDragon:是否需要equals?运算符 == 在这里有效,因为布尔值只有两个值
  • @Atul 是的,这里需要 equals。因为 (new Boolean(true) == new Boolean(true)) 是.... 假的。原因:布尔只是一个类,可以像java中的任何其他类一样有多个实例。
  • 是的,真可惜,构造函数应该是私有的,所以它确保它是一个 twingleton...
  • 这正是 Apache BooleanUtils 的 BooleanUtils.isTrue( bool ); 所做的。
  • 在这个习语上使用 Apache BooleanUtils 绝对没有意义。
【解决方案2】:

当您有boolean 时,它可以是truefalse。然而,当您拥有 Boolean 时,它可以是 Boolean.TRUEBoolean.FALSEnull,就像任何其他对象一样。

在您的特定情况下,您的Booleannull,并且if 语句触发到boolean 的隐式转换,从而产生NullPointerException。您可能需要:

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

【讨论】:

  • 从技术上讲,Boolean 可以是任意数量的真实实例,而不仅仅是 Boolean.TRUE。例如new Boolean(true)
  • 我很难理解为什么if (myBoolean)myBooleanBoolean)不会引发编译器错误或至少是警告。这肯定是个问题。
  • @JoshM。这是因为 Java 对包装器进行了 BoxingUnboxingdocs.oracle.com/javase/tutorial/java/data/autoboxing.html
  • @Vinicius 当然,但在这种情况下编译器应该为我们执行 null,至少通过编译器警告。
【解决方案3】:

使用Apache BooleanUtils

(如果峰值性能是您项目中最重要的优先事项,那么请查看不需要包含外部库的本机解决方案的其他答案之一。)

不要重新发明轮子。利用已经构建的内容并使用isTrue()

BooleanUtils.isTrue( bool );

检查Boolean 的值是否为真,通过返回false 来处理null

如果您不限于“允许”包含的库,那么还有许多适用于各种用例的强大辅助函数,包括 BooleansStrings。我建议您仔细阅读各种 Apache 库,看看它们已经提供了什么。

【讨论】:

  • 当替代方案是使用外部库来实现这样的基本功能时,重新发明轮子似乎并没有那么糟糕。
  • @PaulManta 我同意如果这是您在 Apache Utils 库中曾经唯一使用的东西,但建议的想法是“仔细阅读”这些库以暴露自己到其他有用的功能。
  • 那个库正在重新发明轮子。我尽量避免使用此类库。
  • @mschonaker 如果 Apache BooleanUtils 正在重新发明轮子,那么 original 轮子是什么?这样做的目的是避免创建一堆模仿此类库中已经完成的功能的辅助函数。我还在我的所有应用程序中使用这个库中的toStringYesNo
  • 原轮不是Boolean.TRUE.equals(bool)吗? BooleanUtils 肯定有一些有用的方法,不过你不需要它。
【解决方案4】:

或者借助 Java 8 Optional 的强大功能,您也可以做到这一点:

Optional.ofNullable(boolValue).orElse(false)

:)

【讨论】:

  • 这个答案应该得到更多的认可,但这只是我的意见。
【解决方案5】:

Boolean 类型可以是null。您需要进行null 检查,因为您已将其设置为null

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

【讨论】:

    【解决方案6】:

    Boolean 是原始布尔值的对象包装类。这个类,与任何类一样,确实可以为空。出于性能和内存原因,最好始终使用原语。

    Java API 中的包装类有两个主要用途:

    1. 提供一种在对象中“包装”原始值的机制,以便 原语可以包含在为保留的活动中 对象,例如被添加到集合中,或从 带有对象返回值的方法。
    2. 提供各种 原语的效用函数。这些功能大部分是 与各种转换有关:将原语转换为和从 字符串对象,以及将原语和字符串对象转换为和 来自不同的基数(或基数),例如二进制、八进制和 十六进制。

    http://en.wikipedia.org/wiki/Primitive_wrapper_class

    【讨论】:

      【解决方案7】:

      由于你的变量 bool 指向一个 null,你总是会得到一个 NullPointerException,你需要先用一个非 null 值初始化变量,然后修改它。

      【讨论】:

      • 如果只是这样,catch 块将处理 NullPointerException。这里的问题是 OP 试图将空引用拆箱成原语。
      • "you will always" - 并非总是如此,除了示例,简化的代码在将变量初始化为 null 然后对其进行测试之间不做任何事情.大概真正的代码不会那么简单,或者整个if 测试可以被删除。
      【解决方案8】:

      if (bool) 将被编译为if (bool.booleanValue()),如果boolnull,则会抛出NPE

      可空的盒装布尔评估的其他解决方案:

      • JDK 9+

        import static java.util.Objects.requireNonNullElse;
        
        if (requireNonNullElse(bool, false)) {
            // DoSomething
        
      • 谷歌番石榴 18+

        import static com.google.common.base.MoreObjects.firstNonNull;
        
        if (firstNonNull(bool, false)) {
            // DoSomething
        

      false 在这里用于 null 情况。

      【讨论】:

        【解决方案9】:

        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) {
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-05-09
          • 1970-01-01
          • 2023-04-08
          • 2011-12-03
          • 1970-01-01
          • 1970-01-01
          • 2016-05-10
          相关资源
          最近更新 更多