jdk8 Optional类详解

Optional类应用

介绍

Optional类是JAVA8新增的一个容器类,位于java.util包下。容器类可以理解为一个Optional的实例中包含一个对象实例,然后这个容器类提供一些对这个对象操作的方法,Optional在防止空指针方面得到了广泛的运用。下面会在Optional类和实际运用的时机来介绍。

类的构造和方法剖析

构造方法

​ Optional类一共有两个构造方法

1.私有的构造方法,给value赋一个空值,不对外开放

/**
 * 构造一个空实例。
 * 通常每个虚拟机只应存在一个空实例
 */
private Optional() {
    this.value = null;
}

2.构造一个有值的实例,如果传入的值为空则会抛出NullPointerException异常,同样不对外开放。

/**
 * 构造一个存在值的实例。
 * @param value要存在的非空值。
 * @throws 如果值为null,则会抛出NullPointerException异常。
 */
private Optional(T value) {
    this.value = Objects.requireNonNull(value);
}

成员变量

Optional一共有两个成员变量 “value” 和 “EMPTY” 。value是Optional实例包含的值,EMPTY是value为空的Optional实例。

/**
 * empty()方法返回的公共实例。
 */
private static final Optional<?> EMPTY = new Optional<>();

Optional对象中包裹的值。

private final T value;

成员方法

Optional的成员方法大概可以分为三个类型 “取值” 、 “判断” 和 “构造实例”,下面会逐一介绍。

取值类型方法
  1. get()方法,获取该Optional实例中的包装的值,如果包装值不存在则会抛出NoSuchElementException,如果存在直接返回该值。

    /**
     * 如果此{@code Optional}中存在值,则返回该值,否则就会抛出NoSuchElementException。
     * @return 此{@code Optional}持有的非空值。
     * @throws 如果不存在值,则会抛出NoSuchElementException。
     * @see Optional#isPresent()
     */
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }
    
  2. orElse(T other)方法,获取Optional实例中的包装值,如果值为空则返回other。

    /**
     * 返回值(如果存在),否则返回{@code other}。
     *
     * @param 如果value为空则返回other值,other仍然可能为空
     * @return 如果value存在则返回value,如果value不存在返回other
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }
    
  3. orElseGet(Supplier<? extends T> other)方法,同orElse()方法差不多,区别是orElse()方法如果value不存在返回的是传入的方法参数other,而orElseGet()返回的是传入的函数 ”Supplier“ get之后的结果。

    /**
     * 如果value存在则返回value,如果value不存在则返回 Supplier调用的结果值
     * @param 生产者模式的函数,如果value不存在则返回其结果。
     * @return value存在则返回value,不存在则返回Supplier的计算结果。
     * @throws 如果value和other都为空则抛出NullPointerException
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }
    

    这个方法必须要有java8的函数式接口的知识才能使用,下面举个例子:

    jdk8 Optional类详解

    执行结果:

    jdk8 Optional类详解
  4. orElseThrow(Supplier<? extends X> exceptionSupplier)方法,这个方法的特性是如果value不为空则返回value,如果value为空则通过参数 exceptionSupplier 计算出一个异常类的实例然后抛出。

    /**
     * 如果value存在返回value,如果value不存在则会引发异常,异常实例是由参数exceptionSupplie计算而来。
     * @param 构造异常的工厂模式函数
     * @return 当前Optional实例的value
     * @throws 如果value不存在则会引发异常
     * @throws 如果value和exceptionSupplier都不存在则会引发NullPointerException异常。
     */
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }
    

这个方法跟orElseGet(Supplier<? extends T> other)方法用法相当同样也需要函数式编程的基础,下面举个例子

jdk8 Optional类详解

结果:

jdk8 Optional类详解
  1. ofNullable()方法,该方法的作用是构造一个value可以为空Optional实例

    /**
     * 如果value非空则返回一个包含value值的Optional实例,如果为空则返回一个包含空value的Optional的实例。
     * @param <T> 类型的值
     * @param value值,可能为空
     * @return 返回一个Optional实例。
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
    
  2. of(T value)方法,of方法其实就是调用了内部的Optional(T value)构造函数,所以value不能为空,否则会抛出NullPointerException。

    /**
     * 使用指定的当前非空值返回{@code Optional}。
     * @param <T> 类型的值
     * @param value要存在的值,该值必须非空
     * @return 值存在的{@code Optional}
     * @throws 如果value为空抛出NullPointerException。
     */
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }
    
  3. empty()方法,该方法的作用是返回一个空的Optional实例,该实例是Optional类中的静态成员变量。

    /**
     * 返回一个空的Optional实例
     * @return 空的Optional实例
     */
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
    
  4. map(Function<? super T, ? extends U> mapper) 方法,该方法的作用是通过Function函数接口将T经过计算后转为U的方法,其中U会被包装为Optional类型返回。

    /**
     * 如果某个值存在,则将提供的映射函数应用于该值,如果结果为非null,则返回一个{@code Optional}来描述结果。否则返回一个空的{@code Optional}。
     * @param <U> 映射函数结果的类型
     * @param mapper应用于值的映射函数(如果存在)
     * @return {@code Optional}描述将映射函数应用于此{@code Optional}的值的结果(如果存在值),否则为空{@code Optional}
     * @throws 如果映射函数为null,则发生NullPointerException
     */
    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
    
  5. flatMap(Function<? super T, Optional> mapper) 方法,该方法的作用是和map()方法差不多,只不过flatMap中Function函数的参数泛型必须为Optional类型,但是返回的时候不在包装一层Optional。

    /**
     * 将T通过mapper为U,但是U必须是Optional包装的。
     * @param <U> 返回的{@code Optional}的类型参数
     * @param mapper应用于值的映射函数(如果存在映射函数)
     * @return 如果存在值,则将{@code Optional}的值应用{@code Optional}承载映射函数的结果,否则为空{@code Optional}
     * @throws 如果映射函数为null或返回空结果,则为NullPointerException
     */
    public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }
    
判断类型
  1. isPersend()方法,该方法的作用是判断value是否为空如果为空返回false否则返回true。

    /**
     * 如果存在值,则返回{@code true},否则返回{@code false}。
     * @return 如果存在值{@code true},则为{@code false}。
     */
    public boolean isPresent() {
        return value != null;
    }
    
  2. ifPersend(Consumer<? super T> consumer)方法作用是如果存在值则通过consumer函数消费这个值,否则什么都不做。

    /**
     * 如果存在值,会通过函数消费该值,否则不做任何操作。
     * @param 消费者函数
     * @throws 如果value和函数都为空则抛出NullPointerException。
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
    

    该方法需要掌握函数式编程才能熟练运用,下面是例子

    jdk8 Optional类详解

    结果:控制台输出了哆啦A梦

jdk8 Optional类详解

  1. filter(Predicate<? super T> predicate)方法,该方法的作用是先通过isPersend()方法判断value是否为空,如果value为空则返回当前实例。如果value不为空则使用predicate(value)函数验证value,如果验证结果为true则返回当前Optional实例,如果验证失败则返回空实例。
/**
 * 如果存在一个值,并且该值与给定的谓词匹配,则返回一个描述该值的{@code Optional},否则返回一个空的{@code Optional}。
 * @param 如果value存在则将value应用于判断函数进行判断
 * @return 如果判断结果为true那么返回当前Optional实例否则返回空实例。
 * @throws 如果判断函数为空则抛出NullPointerException
 */
public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}

下面是例子

jdk8 Optional类详解

结果:

jdk8 Optional类详解

脑图

jdk8 Optional类详解

详细脑图地址:http://huatu.98youxi.com/swdt/#R7b18cd527400c284d7ee73f555befedb

总结

Optional已经介绍完了,用好这个类可以有效的避免空指针的尴尬,也可以通过链式调用提升代码的美观度和可读性,jdk9又为该类提供了新的方法,但是此文章只针对jdk8进行讲解,有好奇的伙伴可以去在行查阅。 最后给点个赞吧~

最后会将本文章的markdown文件笔记送给大家。 笔记:http://shaohua-blog.oss-cn-beijing.aliyuncs.com/note/Optional类应用.md

上一篇:Linux 部署 JDK


下一篇:JDK8:HashMap源码解析:put方法