天天看点

Java 8中 Optional 类源码实现与分析

这是《水煮 JDK 源码》系列 的第9篇文章,计划撰写100篇关于JDK源码相关的文章

Optional

类位于

java.util

包下,自 JDK 1.8 版本新增的,它是一个 final 类,不能被继承,且构造函数是 private 的,不能被实例化,它提供了一系列对 null 空值的处理方法,是一个包装类,既可以包装非空对象,也可以包装空值,下面来看看它的定义以及默认构造函数。

public final class Optional<T> {
    private Optional() {
        this.value = null;
    }
}
           

众所周知,在Java开发过程中,经常需要对

null

进行判断和处理,如果漏掉了,就会引发

NullPointerException

异常,因此

null

判断几乎会遍布在代码的每个角落,那么神奇的

null

是如何诞生的呢?

1965年,英国一位名为Tony Hoare的计算机科学家在设计ALGOL W语言时提出了null引用的想法。ALGOL W是第一批在堆上分配记录的类型语言之一。Hoare选择null引用这种方式,“只是因为这种方法实现起来非常容易”。虽然他的设计初衷就是要“通过编译器的自动检测机制,确保所有使用引用的地方都是绝对安全的”,他还是决定为null引用开个绿灯,因为他认为这是为“不存在的值”建模最容易的方式。很多年后,他开始为自己曾经做过这样的决定而后悔不迭,把它称为“我价值百万的重大失误”。(引自网络)

其实,

null

引入的目的是为了表示变量值的缺失。

那么在Java 8 中为什么会引入这样的一个

Optional

类呢?主要是为了对存在或缺失的变量值建模,这样一来,不管变量有没有值,都可以统一使用

Optional

来表示,它可以减少

null

值的判断逻辑,使得代码结构更加简单,同时也可以减少

NullPointerException

异常的出现。

1、构造函数

Optional

类提供了两个构造函数,都是

private

的,如下:

private Optional() {
    this.value = null;
}

private Optional(T value) {
    // value 值不能为 null,否则会抛出空指针异常
    this.value = Objects.requireNonNull(value);
}
           

因为构造函数是私有的,所以不能直接实例化

Optional

类,那么如果创建

Optional

实例呢?可以通过以下的三个方法:

  • empty()

    :通过静态工厂方法创建一个空的

    Optional

    实例;
  • of()

    :将指定值用

    Optional

    封装之后返回,如果该值为

    null

    ,则抛出一个

    NullPointerException

    异常;
  • ofNullable()

    :将指定值用

    Optional

    封装之后返回,如果该值为

    null

    ,则返回一个空的

    Optional

    对象;

2、方法

Optional

类提供了一些方法,主要分为 静态方法和实例方法,像上面提到的三个方法,都是静态方法,主要用于创建

Optional

实例。

2.1 静态方法

(1)empty()

empty()

方法是通过静态工厂方法创建一个空的

Optional

实例,不包含任何值,其定义如下:

private static final Optional<?> EMPTY = new Optional<>();

public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}
           

如果直接调用

empty()

方法,将会直接返回静态常量

EMPTY

.

(2)of()

of()

方法将指定值用

Optional

封装之后返回,如果该值为

null

,则抛出一个

NullPointerException

异常,其源码如下:

public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}
           

直接是通过

new Optional(T value)

方法创建实例,该构造方法使用

Objects.requireNonNull()

对传入的参数进行检查,其源码如下:

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}
           

也就是说

of()

方法不接受

null

空值。

(3)ofNullable()

ofNullable()

方法将指定值用

Optional

封装之后返回,如果该值为

null

,则返回一个空的

Optional

对象,其定义如下:

public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}
           

从实现可以看出,

ofNullable()

方法可以接受

null

空值,而

of()

方法不能接收空值,这也是它与

of()

方法之间的区别。

2.2 实例方法

(1)get()

get()

方法是用来获取

Optional

封装的值的,如果该值存在,将该值用

Optional

封装返回,否则抛出一个

NoSuchElementException

异常,其定义如下:

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

其中的

value

值是

Optional

中的成员变量,其定义如下:

private final T value;
           

(2)isPresent()

isPresent()

方法用于判断

value

值是否存在,如果值存在就返回true,否则返回false,其定义如下:

public boolean isPresent() {
    return value != null;
}
           

(3)ifPresent()

ifPresent()

方法也是用于判断

value

值是否存在,如果值存在,就执行使用该值的方法调用,否则什么也不做,其定义如下:

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}
           

该方法的参数是

Consumer

,如果

value

值存在,则会传入到

Consumer.accept()

方法中,其中

Consumer

类是一个功能性接口,其定义如下:

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
           

(4)filter()

filter()

方法主要用于条件过滤,如果值存在并且满足提供的谓词,就返回包含该值的

Optional

对象;否则返回一个空的

Optional

对象,其定义如下:

public Optional<T> filter(Predicate<? super T> predicate) {
    // filter 方法中的谓词参数不能为空,否则会抛出空指针异常
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}
           

filter()

方法的参数是需要传入一个

Predicate

谓词,并且参数不能为

null

,否则会抛出

NullPointerException

异常,当

value

值存在时,会调用

Predicate.test()

方法进行判断。

(5)map()

map()

方法主要是对

Optional

封装的值执行

mapping

函数,如果值存在,就对该值执行提供的mapping函数调用,如果值不存在,则直接返回空的

Optional

对象,其定义如下:

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    // map 方法中的参数 mapper 函数不能为空,否则会抛出空指针异常
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));
    }
}
           

(6)flatMap()

flatMap()

方法主要也是对

Optional

封装的值执行

mapping

函数,如果值存在,就对该值执行提供的mapping函数调用,返回一个

Optional

类型的值,否则就返回一个空的

Optional

对象,其定义如下:

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    // flatMap 方法中的参数 mapper 函数不能为空,否则会抛出空指针异常
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}
           

flatMap()

方法和

map()

方法有什么区别呢?从方法定义的参数

(7)orElse()

orElse()

方法主要用于如果有值,直接返回,如果没有值时,则返回该方法设置的默认值,其源码如下:

public T orElse(T other) {
    return value != null ? value : other;
}
           

(8)orElseGet()

orElseGet()

方法和

orElse()

方法的作用类似,只是当没有值时,

orElseGet()

方法不是直接返回一个值,而是一个由指定的

Supplier

接口返回的值,其定义如下:

public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}
           

(9)orElseThrow()

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    // 如果值不为 null,直接返回
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}
           

3、其他相关类

  • OptionalInt

    :用于包装整型类;
  • OptionalLong

    :用于包装长整型类;
  • OptionalDouble

    :用于包装Double类型;