Java 上 Boolean.booleanValue 函数的好处或用途?

Benefits or uses for the Boolean.booleanValue function on Java?

所以,我看到了这行代码:

Boolean variable = false;
/* ..stuff.. */
if(variable.booleanValue() == false) {
/* ..more stuff..*/
}

我已经完成了,在不同的地方:

Boolean variable = false;
/* ..my stuff..*/
if(!variable) {
/* ..more of my stuff..*/
}

问题是:第一段代码的 difference/advantages 是什么?

长版本是:鉴于我可以将布尔变量用作原始(布尔)变量,执行 variable.booleanValue() 甚至将其与布尔值进行比较有什么意义?如果变量未初始化,这是否也引入了空指针异常的风险(在代码上不可能,但是嘿)?

在任何情况下都建议使用 variable.booleanValue 以上 "variable"?

两个片段的行为没有区别。

JLS 5.1.8:

At run time, unboxing conversion proceeds as follows:

If r is a reference of type Boolean, then unboxing conversion converts r into r.booleanValue()

因此 if (variable) {...} 将执行为 if (variable.booleanValue()) {...}。因为它们是完全等价的,所以如果 variable == null.

它们都同样容易受到 NPE 的影响

这意味着显式调用 booleanValue() 的一个可能的小优势是您可以立即看到 variable 正在被取消引用,而 variable == false 则不太明显.

是否添加 == false 或取反是个人喜好问题,我更愿意避免使用 == 运算符将布尔表达式与 true 或 [=19= 进行比较].

但我认为更重要的是完全避免 Boolean 并尽可能使用原始类型。

我认为第一种方法相对于第二种方法的唯一优势是可以在 [=12= 之前使用旧的 JDK/Java 语言规范编译代码] 1.5

Boolean 具有三种状态 - truefalsenull。如果你有未初始化的,那么在写 !var 的情况下你将得到 NullPointerException。 还请记住,对象自动初始化为 null 而布尔原语为 false.

区别在于自动拆箱。

第一个版本,最好编码为:

if (variable.booleanValue())

不需要 自动拆箱,因此可以与 Java.

的 1.5 之前版本一起使用

第二个版本,使用自动拆箱,因此需要1.5及以上版本。

如果您的代码需要 运行 和旧 Java 版本,您必须使用版本 1。

两者都可以抛出NPE,所以在这一点上没有区别。

points out the only thing that I can think of to technically make a difference: The second code snippet relies on Autoboxing (or rather auto-unboxing),因此,需要 Java 版本 >= 1.5。

除此之外,没有任何技术差异。你提到

Doesn't this also introduces the risk (on the code impossible, but hey) of a null pointer exception if variable is not initialized?

但是两个版本都是如此。当变量为 null 时,即使是第二个也会抛出 NullPointerException


不过我也对这个很好奇,做了个测试:

public class TheManyShadesOfFasle
{
    public static int testBoxedBooleanBooleanValueComparison()
    {
        Boolean variable = false;
        if(variable.booleanValue() == false)
        {
            return 0;
        }
        return 1;
    }

    public static int testBoxedBooleanComparison()
    {
        Boolean variable = false;
        if(variable == Boolean.FALSE)
        {
            return 0;
        }
        return 1;
    }

    public static int testBoxedBooleanBooleanValueDirect()
    {
        Boolean variable = false;
        if(!variable.booleanValue())
        {
            return 0;
        }
        return 1;
    }

    public static int testBoxedBooleanDirect()
    {
        Boolean variable = false;
        if(!variable)
        {
            return 0;
        }
        return 1;
    }

    public static int testBooleanComparison()
    {
        boolean variable = false;
        if(variable == false)
        {
            return 0;
        }
        return 1;
    }

    public static int testBooleanDirect()
    {
        boolean variable = false;
        if(!variable)
        {
            return 0;
        }
        return 1;
    }

}

可以用javap -c反编译得到字节码:

  public static int testBoxedBooleanBooleanValueComparison();
    Code:
       0: iconst_0
       1: invokestatic  #2                  // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
       4: astore_0
       5: aload_0
       6: invokevirtual #3                  // Method java/lang/Boolean.booleanValue:()Z
       9: ifne          14
      12: iconst_0
      13: ireturn
      14: iconst_1
      15: ireturn

  public static int testBoxedBooleanComparison();
    Code:
       0: iconst_0
       1: invokestatic  #2                  // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
       4: astore_0
       5: aload_0
       6: getstatic     #4                  // Field java/lang/Boolean.FALSE:Ljava/lang/Boolean;
       9: if_acmpne     14
      12: iconst_0
      13: ireturn
      14: iconst_1
      15: ireturn

  public static int testBoxedBooleanBooleanValueDirect();
    Code:
       0: iconst_0
       1: invokestatic  #2                  // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
       4: astore_0
       5: aload_0
       6: invokevirtual #3                  // Method java/lang/Boolean.booleanValue:()Z
       9: ifne          14
      12: iconst_0
      13: ireturn
      14: iconst_1
      15: ireturn

  public static int testBoxedBooleanDirect();
    Code:
       0: iconst_0
       1: invokestatic  #2                  // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
       4: astore_0
       5: aload_0
       6: invokevirtual #3                  // Method java/lang/Boolean.booleanValue:()Z
       9: ifne          14
      12: iconst_0
      13: ireturn
      14: iconst_1
      15: ireturn

  public static int testBooleanComparison();
    Code:
       0: iconst_0
       1: istore_0
       2: iload_0
       3: ifne          8
       6: iconst_0
       7: ireturn
       8: iconst_1
       9: ireturn

  public static int testBooleanDirect();
    Code:
       0: iconst_0
       1: istore_0
       2: iload_0
       3: ifne          8
       6: iconst_0
       7: ireturn
       8: iconst_1
       9: ireturn

并且可以看到 testBoxedBooleanBooleanValueComparisontestBoxedBooleanDirect 的字节码(对应你的第一和第二个代码片段)相同。 (这基本上意味着:自动拆箱是 隐式地 调用 Boolean 内部的 booleanValue 方法)。 if(!variable.booleanValue())也一样,在testBoxedBooleanBooleanValueDirect中可以看出。

其他案例主要是为了完整性:testBooleanComparisontestBooleanDirect 案例都有相同的字节码,但它与其他案例不同,因为没有发生拆箱或取消引用。


一个案例可能值得指出:将变量与 Boolean.FALSEBoolean.TRUE 进行比较是有意义的,因为它隐含地涵盖了变量为 null 的情况:

if (variable == Boolean.TRUE) {
    ...
} else {
    // Here, the variable is either "false" or "null"
}

if (variable == Boolean.FALSE) {
    ...
} else {
    // Here, the variable is either "true" or "null"
}