跳至主要內容

Boolean 还是 boolean?

JavaDaily

Boolean 还是 boolean?

在 Java 中,对于布尔类型的变量、对象属性或方法参数的定义,到底是用包装类型 Boolean 还是基本类型 boolean 呢?

结论

先说结论:根据《Effective Java》(第三版),始终尽可能地使用基本类型。故应该使用 boolean。

原文如下:

红线处翻译:总结就是,当你有得选的时候,请务必使用基本类型,而非包装类型。

那什么时候使用包装类型呢?原文如下:

红线处翻译:当你没得选、被强制要求时,才使用包装类型。如:使用泛型(使用集合类、调用参数是泛型参数的方法),以及通过反射进行方法调用(使用 invoke 方法)

争议

阿里的《Java开发手册》open in new window有提到,类属性强制使用包装类型。

但注意,本文讨论的仅仅是布尔类型,不要发散话题。 那现在就来分析一下,布尔类型有没有必要考虑 null 的情况?

我认为是没有的必要的。理由如下:

  • 布尔类型就是二进制的,代码两种情况:1或0;真或假。使用包装类型,出现第三种情况 null,不但要注意空指针异常问题,还要兼容 null 的情况——此时到底是真还是假呢?
  • 如果 null 表示的既不是真也不假,而是第三种情况——就不该定义为布尔类型,而应定义为枚举类型,因为一共有三种情况。使用 Boolean 来表示三种情况,是设计上的偷懒。

实战

我们来看一下实际代码中,滥用 Boolean 类型导致的问题。

简单例子

有如下 Controller,使用的是 boolean:

@RestController
public class DemoController {
  @RequestMapping("/hello")
  public String hello(boolean bool) {
   return String.valueOf(bool) ;
  }
}

前端传个空值,会得到报错信息:

但如果使用 Boolean,并不能检查出是非法参数:

这原本是前端传参错误,但却无法即使发现。

你可能会问,为什么不先判断 Boolean 变量是否为 null 呢?因为别人在声明 Boolean 变量时,设置了默认值为 false,谁能想到前端会传个 null?

这就是 Boolean 的问题:“千防万防,家贼难防”!

复杂例子

下面是前端传给 Controller 的参数:

public class TableQuery {
    private Boolean withTable2Api;
    private Boolean forkable;
}	

需要注意的是,有至少两个 Controller 会接受到了这个参数,并且根据业务的不同,它们对参数的处理是不同的:

  • 有的会判断如果 withTable2Api 为 null,就设置为 true
  • 有的则完全由前端传值,也即 forkable、withTable2Api 有可能为 null

来看一下,Service 里的相应代码:

这里有什么问题呢?可以看到,第二个 if 使用 !Boolean._TRUE_去判断很别扭,然而,却不能改写成:

// 错误!因为没有兼容 null 的情况
if (Boolean.FALSE.equals(query.getWithTable2Api())) {
   
}

这就是布尔值使用 Boolean 类型在实战中最大的问题——你不能任意地进行真或假的判断,而必须兼容上下文中隐式对 null 赋予的含义。

而多人协作过程中,外部调用是很难控制的,因此,此时使用 Boolean,只增加了无谓的编码负担。

Joshua Bloch - Effective Java (3rd) - 2018.pdfopen in new window

上次编辑于:
贡献者: levy