关于前端:Java-8中-Optional-类源码实现与分析

1次阅读

共计 4545 个字符,预计需要花费 12 分钟才能阅读完成。

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()

orElseThrow() 办法用于如果有值,则间接返回,如果没有值,则间接抛出一个由指定的 Supplier 接口生成的异样,其定义如下:

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

3、其余相干类

除了 Optional 类外,java.util 包下还提供了另外的三个根底类型的 Optional 类,如下:

OptionalInt
OptionalLong
OptionalDouble

这三个类的源码与 Optional 相似,只是 Optional 类应用了泛型定义,而它们只能利用于根底数据类型。

正文完
 0