Java8实战使用Optional取代null

Posted houJINye

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java8实战使用Optional取代null相关的知识,希望对你有一定的参考价值。

在Java中对一个空对象进行操作时,便会抛出最常见的异常NullPointerException。为了改善这个问题,Java 8中提供了一个java.util.Optional<T>类型。Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。下面介绍Optional类的使用方法。 假如有一个像下面这样的类层次结构:

class Department {
  private Employee employee;
  public Department(Employee employee) {
      this.employee = employee;
  }
  Employee getEmployee() {
      return employee;
  }
}
?
class Employee {
  private Girl girlFriend;
  public Employee(Girl girlFriend) {
      this.girlFriend = girlFriend;
  }
  Girl getGirlFriend() {
      return girlFriend;
  }
}
?
class Girl {
  private String name;
  public Girl(String name) {
      this.name = name;
  }
  String getName() {
      return name;
  }
}

 

部门Department类包含一个员工employee属性,类型为Employee,员工Employee类包含girlFriend属性,类型为Girl。假如现在要获取部门某个员工的女朋友,我们通常是这样获取的:

static String getGirlFriendName(Department department) {
  if (department != null) {
      Employee employee = department.getEmployee();
      if (employee != null) {
          Girl girl = employee.getGirlFriend();
          if (girl != null) {
              return girl.getName();
          }
          return "单身汪";
      }
      return "没有员工";
  }
  return "部门为空";
}

 

可以看到,在每次引用变量的属性时,都要先判断变量是否为空,如果不做该检查将可能导致NullPointerException。下面我们将使用Optional来改善这种层层嵌套,啰嗦的代码。

创建Optional

创建一个Optional对象有好几种方式:

创建一个空的Optional

我们可以使用静态工厂方法Optional.empty,创建一个空的Optional对象:

Optional<Department> department = Optional.empty();

 

根据非空值创建Optional

我们也可以使用静态工厂方法Optional.of来创建一个非空对象的Optional对象:

Optional<Employee> optEmployee = Optional.of(employee);

 

如果employee为空,这段代码会立即抛出一个NullPointerException

创建可以为null的Optional

使用静态工厂方法Optional.ofNullable,我们可以创建一个允许null值的Optional对象:

Optional<Employee> optEmployee = Optional.ofNullable(employee);

 

如果employee为空,对其调用get方法将抛出NoSuchElementException

Optional方法

Optional类包含了许多方法,下面介绍这些方法的使用。

isPresent

顾名思义,如果值存在返回true,否则返回false。如:

 Optional<Department> opt = Optional.ofNullable(department);
if(opt.isPresent()){
  System.out.println(opt.get().getEmployee());
}

 

get

如果Optional有值则将其返回,否则抛出NoSuchElementException。下面举个抛出NoSuchElementException的例子:

try {
  Optional.empty().get();
} catch (Exception e) {
  e.printStackTrace();
}

 

代码将捕获到 java.util.NoSuchElementException: No value present 异常。

ifPresent

如果Optional实例有值则为其调用Consumer(函数描述符为T -> void),否则不做处理。如:

girl.ifPresent(g -> System.out.println("我有女朋友,名字是:" + g.getName()));

 

orElse

如果Optional实例有值则将其返回,否则返回orElse方法传入的参数。如:

System.out.println(Optional.empty().orElse("There is no value present!"));

 

程序将输出There is no value present!

orElseGet

orElseGetorElse方法类似,orElse方法将传入的字符串作为默认值,而orElseGet方法可以接受Supplier(函数描述符为() -> T)来生成默认值。如:

System.out.println(Optional.empty().orElseGet(() -> "There is no value present!"));

 

程序同样输出There is no value present!

orElseThrow

如果有值则将其返回,否则抛出Supplier接口创建的异常。如:

try {
  Optional.empty().orElseThrow(NoSuchElementException::new);
} catch (Exception e) {
  e.printStackTrace();
}

 

代码将捕获到 java.util.NoSuchElementException: No value present 异常。

map

如果Optional有值,则对其执行调用Function函数描述符为(T -> R)得到返回值。如果返回值不为null,则创建包含Function回值的Optional作为map方法返回值,否则返回空Optional。

Optional<String> upperName = name.map(String::toUpperCase);
System.out.println(upperName.orElse("No value found"));

 

flatMap

如果有值,为其执行Function函数返回Optional类型返回值,否则返回空Optional。flatMapmap方法类似,区别在于flatMap中的Function函数返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。如:

upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));

 

filter

filter个方法通过传入Predicate(函数描述符为T -> Boolean)对Optional实例的值进行过滤。如:

Optional<String> name = Optional.of("Jane");
Optional<String> LongName = name.filter((value) -> value.length() >= 3);
System.out.println(LongName.orElse("名字长度小于3个字符"));

 

方法输出Jane

实战

介绍完Optional类的方法后,我们使用Optional改善一开始的代码:

static String getGirlFriendName(Department department) {
  Optional<Department> opt = Optional.ofNullable(department);
  return opt.map(Department::getEmployee)
          .map(Employee::getGirlFriend)
          .map(Girl::getName)
          .orElseThrow(NoSuchElementException::new);
}

 

整洁而又不失逼格。

以上是关于Java8实战使用Optional取代null的主要内容,如果未能解决你的问题,请参考以下文章

《Java8实战》读书笔记09:用 Optional 处理值为 null 的情况

用optional取代null

Java8中你可能不知道的一些地方之Optional实战

Java8中你可能不知道的一些地方之Stream实战

Java8新特性之:Optional

JAVA8之妙用Optional解决判断Null为空的问题