Java 8 基础教程 - Optional

2,433 阅读3分钟
原文链接: www.codemore.top

对于Java开发者肯定遇到过 NullPointerException 这个异常。在Java中Null是非常常见的,例如默认类的字段被初始化为null。

返回null会发生什么问题

一般来讲API的设计者会在Javadoc中详细介绍会返回null的方法,但是使用者很有可能没有详细阅读Javadoc从而忽略了这个问题,这就会导致使用者使用API的时候忘记进行null检测。从而导致抛出 NullPointerException。

在Java 8 中如何解决这个问题

Java 8引入了Optional来解决null的问题,一个Optional要么包含一个非空的引用对象,要么什么都不包含。注意,这里说的什么都不包含,并不是说Optional包含了null。

Optional<Integer> canBeEmpty1 = Optional.of(5);
canBeEmpty1.isPresent();                    // returns true
canBeEmpty1.get();                          // returns 5
 
Optional<Integer> canBeEmpty2 = Optional.empty();
canBeEmpty2.isPresent();                    // returns false

可以将Optional看作单值容器,要么包含一个值,要么不包含。注意,Optional并不能完全替代所有的null引用,它的主要作用是用来设计更易理解的API,当一个函数返回的是Optional的时候,调用者就会注意需要检测其是否有值才能够调用。

使用Optional
创建Optional对象

主要有三种创建Optional对象的方法 1. 使用 Optional.empty() 创建一个空的Optional

Optional<Integer> possible = Optional.empty();
  1. 使用Optional.of() 创建一个非null的值。
Optional<Integer> possible = Optional.of(5);
  1. 使用Optional.ofNullable() 创建一个可以包含空值的Optional对象,如果参数是null,则返回一个空的Optional
Optional<Integer> possible = Optional.ofNullable(null);
//or
Optional<Integer> possible = Optional.ofNullable(5);
处理Optional的值

当得到一个Optional的值的时候,首先需要检查其是否包含了值

Optional<Integer> possible = Optional.of(5);
possible.ifPresent(System.out::println);

当然上面的代码也可以通过下面的方式重写:

if(possible.isPresent()){
    System.out.println(possible.get());
}

不过这么做并不推荐,因为这个处理null没啥区别。推荐使用上面的代码

返回Optional

一般来讲对于方法如果最终需要返回null的时候,都会返回一个默认值以便替换null,使用Optional可以使用如下的方式返回

Optional<Company> companyOptional = Optional.empty();
// 检查Optional,如果有值直接返回,否则返回 new Company();
Company company = companyOptional.orElse(new Company());
// 检查Optional,如果有值直接返回,否则返回 抛出异常;
Company company = companyOptional.orElseThrow(IllegalStateException::new);
在Filter中使用Optional

例如:

Optional<Company> companyOptional = Optional.empty();
companyOptional.filter(department -> "Finance".equals(department.getName())
                    .ifPresent(() -> System.out.println("Finance is present"));)

filter 函数接受一个Predicate接口作为参数,如果Optional中存在值,那么就会匹配直接输出。

深入理解Optional

在Optional.java 中,Optional的定义如下:

/**
 * If non-null, the value; if null, indicates no value is present
 */
private final T value;

如果定义的是一个空的Optional,则直接返回EMPTY的常量

/**
 * Common instance for {@code empty()}.
 */
private static final Optional<?> EMPTY = new Optional<>();

当创建一个Optional的时候调用:

this.value = Objects.requireNonNull(value);

从Optional获取值的时候:

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}
结论

Optional 的目的并不是要完全替代null引用,而且为了设计更友好的API而设计的。