Java8中的Optional

902 阅读19分钟

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。 Optional 类是个容器,它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。 Optional 类的引入很好的解决空指针异常(NullPointerException)。

Optional 类位于java.util.Optional包下,类似Optional的还有OptionalDoubleOptionalIntOptionalLong Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。但是 Optional 的意义显然不止于此。

一、类签名

/**
 * 可能包含也可能不包含非空值的容器对象。 如果存在值,isPresent()将返回true ,get()将返回该值。
 *
 * 提供了依赖于包含值的存在与否的其他方法,例如orElse() (如果值不存在则返回默认值和ifPresent() (如果值存在则执行代码块)。
 *
 * 这是一个基于值的类;在Optional实例上使用身份敏感操作(包括引用相等性 ( == )、身份哈希码或同步)可能会产生不可预测的结果,应该避免。
 *
 * @since 1.8
 */
public final class Optional<T> extends Object{};

二、类中的方法

1、静态方法

方法定义描述
public static<T> Optional<T> empty()返回一个空的Optional实例。 此可选项不存在值。
public static <T> Optional<T> of(T value)返回具有 Optional的当前非空值的Optional。
public static <T> Optional<T> ofNullable(T value)返回一个 Optional指定值的Optional,如果非空,则返回一个空的 Optional

2、具体方法

方法定义描述
public T get()如果 Optional中存在值,则返回值,否则抛出 NoSuchElementException
public boolean isPresent()如果存在值,则返回 true ,否则为 false
public void ifPresent(Consumer<? super T> consumer)如果存在值,则使用该值调用指定的消费者,否则不执行任何操作。
public Optional<T> filter(Predicate<? super T> predicate)如果一个值存在,并且该值给定的谓词相匹配时,返回一个 Optional描述的值,否则返回一个空的 Optional
public<U> Optional<U> map(Function<? super T, ? extends U> mapper)如果存在值,则应用提供的映射函数,如果结果不为空,则返回一个Optional结果的Optional 。 否则返回一个空的Optional
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)如果一个值存在,应用提供的Optional映射函数给它,返回该结果,否则返回一个空的Optional 。 这种方法类似于map(Function) ,但是提供的映射器是一个结果已经是Optional映射器,如果被调用, flatMap不会用额外的Optional
public T orElse(T other)返回值如果存在,否则返回 other
public T orElseGet(Supplier<? extends T> other)返回值(如果存在),否则调用 other并返回该调用的结果。
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
public boolean equals(Object obj) 指示某个其他对象是否等于此可选项
public int hashCode()返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
public String toString()返回此可选的非空字符串表示,适用于调试。 准确的表示格式是未指定的,可能会在实现和版本之间变化。

四、JDK8以前解决空指针

在jdk8以前我们为了避免空指针,我们一般是对每一个操作的对象进行非空判断,,否则就会让你体验一下非定时炸弹NullPointerException异常

main方法

/**
 * 创建 Optional  实例
 *
 * @author Minhat
 */
public class OptionalTest {
    public static void main(String[] args) {
        jdk8BeforeUsage();
    }

    /**
     * 在 Java 8 之前,任何访问对象方法或属性的调用都可能导致NullPointerException
     */
    public static void jdk8BeforeUsage() {
        User1 user1 = null;
        if (user != null) {
            String username = user.getUsername();
            if (username != null) {
				System.out.println("用户名为:" + username);
            }
        }
    }
}

用户类

/**
 * 用户类
 *
 * @author Minhat
 */
@Data
public class User1 {
    /**
     * 用户名
     */
    private String username;
}

以上代码为了解决空指针异常,对每一个对象都进行了非空判断,如果对象引用层数少看似没什么影响,但是如果一个对象A引用对象B引用对象C,那么我们获取C对象时就要写V字大法的判断了:

if(a != null) {
    if(b != null) {
        if(c != null) {
            if(d != null) {
                if(d != null) {
                    if(e != null) {
                        if(f != null) {
                            ...
                        	// 只要你够任性的挑剔对象,那么你总有一天会找到属于你的真爱对象
                    	}
                    }
                }
            }
        }
    }
}

当你看到这样的代码是不是,大写一个我艹,太难维护了;为了简化这个过程我们来看看用 Optional 类是怎么做的。从创建和验证实例,到使用其不同的方法,并与其它返回相同类型的方法相结合,下面是吸收一下 Optional 骚操作。

五、创建Optional实例

如何创建一个Optional实例呢?下面我们来看一下Optional的构造方法源码:

/**
* 构造一个空实例。
*
* @implNote 通常,每个VM应该只存在一个空实例EMPTY 。
*/
private Optional() {
	this.value = null;
}

/**
*构造一个具有当前值的实例。
*
* @param value 要存在的非空值
* @throws NullPointerException 如果值为null
*/
private Optional(T value) {
    this.value = Objects.requireNonNull(value);
}

对你没看错,构造方法都被私有化了,貌似看来你永远也得不到Optional这个对象,但是请转移你的目光,既然不能直接直接得创建实例,那么我们再来看看有没有其他方式呢,下面我们来一探究竟。

1、Optional.empty()

Optional.empty()的对象可以包含值,也可以值为空,你可以是用静态方法empty()创建一个空的Optional对象。

(1)、构造方法签名

/**
* 返回一个空的Optional实例。 此可选项不存在值。
*
* @apiNote 尽管这样做可能很诱人,但避免通过将==与Option.empty()返回的实例进行比较来测试对象是否为空。
* 不能保证它是单例。 相反,使用isPresent() 。
*
* @param <T> 不存在值的类型
* @return 一个空的 Optional
*/
public static<T> Optional<T> empty();

(2)、示例代码

/**
* 使用Optional.empty()创建一个空值为空的Optional对象
*/
public static void useEmptyCreateOptional() {
    Optional<Object> empty = Optional.empty();
    // 使用Optional的isPresent()方法判断Optional的值是否为空
System.out.println("Optional的值是否为空:" + empty.isPresent());
}

(3)、运行结果

Optional的值是否为空:false

Process finished with exit code 0

从运行结果可以看出Optional的值为空。

2、Optional.of(T value)

Optional.of(T value)返回具有 Optional的当前非空值的Optional。传入的value的值不能为null,如果value的值为空则抛出NullPointerException异常。

(1)、构造方法签名

/**
* 返回具有Optional的当前非空值的Optional。
*
* @param 要存在的值,它必须是非空值
* @throws NullPointerException 如果值为空抛出
*/
public static <T> Optional<T> of(T value);

(2)、示例代码

/**
* 使用Optional.of()创建Optional对象
*/
public static void useOfCreateOptional() {
    // 创建一个非空的Optional对象,不会抛出空指针异常
    Optional<String> notNullOpt = Optional.of("小红帽");
	System.out.println("Optional的值是否为空:" + notNullOpt.isPresent());

	 // 创建一个空的Optional对象,会抛出空指针异常
    Optional<String> isNullOpt = Optional.of(null);
    System.out.println("Optional的值是否为空:" + isNullOpt.isPresent());
}

(3)、运行结果

Optional的值是否为空:true
Exception in thread "main" java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	at java.util.Optional.<init>(Optional.java:96)
	at java.util.Optional.of(Optional.java:108)
	at cn.minhat.other.OptionalTest.userOfCreateOptional(OptionalTest.java:48)
	at cn.minhat.other.OptionalTest.main(OptionalTest.java:14)

Process finished with exit code 1

从运行结果中可以看出如果Optional.of(T),传入的参数不为空不会抛出空指针异常,如果传入的值为null则抛出空指针异常。因此在是用Optional.of()`方法是要确保传入的对象不能为空否则就会抛出空指针异常。

3、Optional.ofNullable(T value)

Optional.ofNullable(T value)返回一个 Optional指定值的Optional,如果非空,则返回一个空的 Optional 。使用该方法即使value为空也不会发生任何异常。

(1)、构造方法签名

/**
* 返回一个 Optional指定值的Optional,如果非空,则返回一个空的 Optional 。
*
* @param <T> 该类的值
* @param value 可能为null的值来描述
* @return 一个Optional,如果指定的值不为空,则为当前值,否则为空 Optional
*/
public static <T> Optional<T> ofNullable(T value);

(2)、示例代码

/**
* 使用Optional.ofNullable()创建Optional对象
*/
public static void useOfNullableCreateOptional() {
    // 创建一个非空的Optional对象,不会抛出空指针异常
    Optional<String> notNullOpt = Optional.ofNullable("小红帽");
    System.out.println("Optional的值是否为空:" + notNullOpt.isPresent());

    // 创建一个空的Optional对象,会抛出空指针异常
    Optional<String> isNullOpt = Optional.ofNullable(null);
    System.out.println("Optional的值是否为空:" + isNullOpt.isPresent());
}

(3)、运行结果

Optional的值是否为空:true
Optional的值是否为空:false

Process finished with exit code 0

从运行结果中可以看出使用Optional.ofNullable(T)创建Optional的对象,不管传入的值是否为null都不会报错。因此在使用Optional.ofNullable(T)方法是通常处理我们不确定传入的参数是否为空的值。

六、Optional的具体方法

1、get()

get()如果此Optional存在值,则返回该值,否则抛出NoSuchElementException 。

(1)、方法签名

/**
* 如果Optional中存在值,则返回值,否则抛出 NoSuchElementException 。
*
* @return 该Optional非空值
* @throws NoSuchElementException 如果没有值存在
*
* @see Optional#isPresent()
*/
public T get();

(2)、示例代码

/**
* 使用Optional的get()方法。
* 如果 Optional中存在值,则返回值,否则抛出NoSuchElementException 。
*/
public static void useGetMethod() {
    // 创建一个非空的Optional对象
    Optional<String> notNullOpt = Optional.of("小红帽");
    System.out.println("Optional中的值:" + notNullOpt.get());

    // 创建一个空的Optional对象
    Optional<String> isNullOpt = Optional.empty();
    System.out.println("Optional中的值:" + isNullOpt.get());
}

(3)、运行结果

Optional中的值:小红帽
Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at cn.minhat.other.OptionalTest.useGetMethod(OptionalTest.java:78)
	at cn.minhat.other.OptionalTest.main(OptionalTest.java:16)

Process finished with exit code 1

可以看出我们使用get()方法获取Optional的值如果Optional中存在值,则返回值,否则抛出 NoSuchElementException 。

2、isPresent()判断只是否存在

isPresent()如果存在值,则返回 true ,否则为 false

(1)、方法签名

/**
* 如果存在值,则返回true,否则为false 。
*
* @return true若有存在值,否则为false
*/
public boolean isPresent();

(2)、示例代码

/**
* 使用Optional的isPresent()方法。
* 如果存在值,则返回 `true` ,否则为 `false` 。
*/
public static void useIsPresentMethod() {
    // 创建一个非空的Optional对象
    Optional<String> notNullOpt = Optional.of("小红帽");
    System.out.println("Optional中是否有值:" + notNullOpt.isPresent());

    // 创建一个空的Optional对象
    Optional<String> isNullOpt = Optional.empty();
    System.out.println("Optional中是否有值:" + isNullOpt.isPresent());
}

(3)、运行结果

Optional中是否有值:true
Optional中是否有值:false

Process finished with exit code 0

3、ifPresent(Consumer<? super T> consumer)

ifPresent(Consumer<? super T> consumer)如果存在值,则使用该值就调用Consume函数式接口,否则不执行任何操作。如果值存在且consumer为空则抛出NullPointerException异常。

(1)、方法签名

/**
* 如果存在值,则使用该值调用指定的Consumer,否则不执行任何操作。
*
* @param consumer 如果存在值,则执行Consumer
* @throws NullPointerException 如果值不为Null,consumer为空
*/
public void ifPresent(Consumer<? super T> consumer);

(2)、示例代码

/**
* 使用Optional的ifPresent()方法。
* 如果存在值,则使用该值调用指定的消费者,否则不执行任何操作。
* 如果值存在且Consumer为空则抛出NullPointerException异常。
*/
public static void useIfPresent() {
    // 创建一个非空的Optional对象
    Optional<String> notNullOpt = Optional.of("小红帽");
    notNullOpt.ifPresent(s -> System.out.println("调用了Consumer接口"));

    // 创建一个空的Optional对象
    Optional<String> isNullOpt = Optional.empty();
    isNullOpt.ifPresent(s -> System.out.println("调用了Consumer接口"));

    // 使用值非空的Optional调用ifPresent,传入null的Consumer
    notNullOpt.ifPresent(null);
}

(3)、运行结果

调用了Consumer接口
Exception in thread "main" java.lang.NullPointerException
	at java.util.Optional.ifPresent(Optional.java:159)
	at cn.minhat.other.OptionalTest.useIfPresent(OptionalTest.java:112)
	at cn.minhat.other.OptionalTest.main(OptionalTest.java:18)

Process finished with exit code 1

从运行结果可以看出:

  • Optional的值不为空并且Consumer不为空,ifPresent方法不会发生任何异常并且调用Consumer函数式接口
  • Optional的值为空但是Consumer不为空,ifPresent方法不会发生任何异常但是不调用Consumer函数式接口
  • Optional的值不为空但是Consumer为空,ifPresent会直接抛出NullPointerException异常

4、filter(Predicate<? super T> predicate)

此方法的作用是单签的Optional实例不为空,则执行函数式接口Predicate,如果满足条件则返回当前的Optional实例否则返回一个空的Optional实例。

filter(Predicate<? super T> predicate)有以下特性:

  • 如果Optional的值不为空,并且Predicate函数式接口返回为true则返回当前的Optional
  • 如果Optional的值不为空,并且Predicate函数式接口返回为true则返回一个空Optional
  • 如果Optional的值为空则返回当前的Optional
  • 如果函数式接口Predicate为空则直接抛出NullPointerException异常

(1)、方法签名

/**
* 如果一个值存在,并且该值给定的谓词相匹配时,返回一个 Optional描述的值,否则返回一个空的 Optional 。
*
* @param 一个应用于该值的Predicate(如果存在)
* @return 一个 Optional描述此的值 Optional一个值是否存在,并且值给定的Predicate相匹配,否则一个空 Optional
* @throws NullPointerException 如果Predicate为空
*/
public Optional<T> filter(Predicate<? super T> predicate);

(2)、示例代码

/**
* 使用Optional的filter()方法。
* 如果函数式接口Predicate为空则直接抛出NullPointerException异常
* 如果Optional的值不为空,并且Predicate函数式接口返回为true则返回当前的Optional
* 如果Optional的值不为空,并且Predicate函数式接口返回为true则返回一个空Optional
* 如果Optional的值为空则返回当前的Optional
*/
public static void useFilter() {
    // 创建一个非空的Optional对象
    Optional<String> notNullOpt = Optional.of("小红帽");
    // Predicate返回true
    System.out.println("Optional中是否有值:" + notNullOpt.filter(s -> true).isPresent());
    // Predicate返回false
    System.out.println("Optional中是否有值:" + notNullOpt.filter(s -> false).isPresent());

    // 创建一个空的Optional对象
    Optional<String> isNullOpt = Optional.empty();
    // Predicate返回true
    System.out.println("Optional中是否有值:" + isNullOpt.filter(s -> true).isPresent());

    // 传入Null的Predicate
    System.out.println("Optional中是否有值:" + notNullOpt.filter(null).isPresent());
}

(3)、运行结果

Optional中是否有值:true
Optional中是否有值:false
Optional中是否有值:false
Exception in thread "main" java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	at java.util.Optional.filter(Optional.java:174)
	at cn.minhat.other.OptionalTest.useFilter(OptionalTest.java:137)
	at cn.minhat.other.OptionalTest.main(OptionalTest.java:19)

Process finished with exit code 1

5、map(Function<? super T, ? extends U> mapper)

如果存在值,则对其应用提供的Function函数接口,如果结果非空,则返回描述结果的Optional 。 否则返回一个空的Optional 。

(1)、方法签名

/**
* 如果存在值,则应用提供的映射函数,如果结果不为空,则返回一个Optional结果的Optional 。 否则返回一个空的Optional 。
*
* @apiNote 此方法支持对可选值进行后处理,无需明确检查返回状态。 例如,以下代码遍历文件名流,选择尚未处理的代码,
* 然后打开该文件,返回Optional<FileInputStream>
*
* <pre>{@code
*     Optional<FileInputStream> fis =
*         names.stream().filter(name -> !isProcessedYet(name))
*                       .findFirst()
*                       .map(name -> new FileInputStream(name));
* }</pre>
*
* 这里, findFirst返回一个Optional<String> ,然后map返回一个Optional<FileInputStream>为所需文件(如果存在)。
*
* @param <U> 映射函数的结果类型
* @param mapper 应用于值的映射函数(如果存在)
* @return 一个 Optional描述了将映射函数应用于该值 Optional的值的 Optional ,如果存在值,否则为空 Optional
* @throws NullPointerException 如果映射函数为空
*/
public<U> Optional<U> map(Function<? super T, ? extends U> mapper);

(2)、示例代码

/**
* 使用Optional的map()方法。
* 如果传入的Function函数式接口为空则抛出NullPointerException异常。
* 如果Optional的值为null则返回空的Optional。
* 如果Optional的值不为null则调用函数式接口Function,如果函数式接口返回的值为null,则返回空的Optional。
* 如果Optional的值不为null则调用函数式接口Function,如果不为null则返回函数式接口返回的值的Optional实例。
*/
public static void useMap() {
    // 如果传入的Function函数式接口为空则抛出NullPointerException异常。
    Optional<String> notNullOpt = Optional.of("小红帽");
    try {
        notNullOpt.map(null);
    } catch (NullPointerException e) {
        e.printStackTrace();
    }

    // 如果Optional的值为null则返回空的Optional。
    Optional<String> isNullOpt = Optional.empty();
    Optional<String> result_1 = isNullOpt.map(s -> "测试:" + s);
    System.out.println("Optional中是否有值:" + result_1.isPresent());

    // 如果Optional的值不为null则调用函数式接口Function,如果函数式接口返回的值为null。
    Optional<Object> result_2 = notNullOpt.map(s -> null);
    System.out.println("Optional中是否有值:" + result_2.isPresent());

    // 如果Optional的值不为null则调用函数式接口Function,如果不为空则返回函数式接口返回的值的Optional实例。
    Optional<Object> result_3 = notNullOpt.map(s -> "测试:" + s);
    System.out.println("Optional中是否有值:" + result_3.isPresent() + ",值为:" + result_3.get());
}

(3)、运行结果

java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	at java.util.Optional.map(Optional.java:211)
	at cn.minhat.other.OptionalTest.useMap(OptionalTest.java:151)
	at cn.minhat.other.OptionalTest.main(OptionalTest.java:20)
Optional中是否有值:false
Optional中是否有值:false
Optional中是否有值:true,值为:测试:小红帽

Process finished with exit code 0

5、flatMap(Function<? super T, Optional> mapper)

如果存在一个值,则将提供的Optional承载映射函数应用于它,返回该结果,否则返回一个空的Optional 。 此方法类似于map(Function) ,但提供的映射器的结果已经是Optional ,并且如果调用, flatMap不会用额外的Optional包装它。

(1)、方法签名

/**
* 如果一个值存在,应用提供的Optional映射函数给它,返回该结果,否则返回一个空的Optional 。 
* 这种方法类似于map(Function) ,但是提供的映射器是一个结果已经是Optional映射器,
* 如果被调用, flatMap不会用额外的Optional 。
*
* @param <U> 返回的 Optional的类型参数
* @param mapper 应用于值的映射函数,如果存在映射函数
* @return 施加的结果 Optional荷瘤映射函数此的值 Optional ,如果一个值存在,否则一个空 Optional
* @throws NullPointerException 如果映射函数为空或返回空结果
*/
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper);

(2)、示例代码

/**
* 使用Optional的flatMap()方法。
* 如果传入的Function函数式接口为空则抛出NullPointerException异常。
* 如果Optional的值为null则返回空的Optional。
* 如果Optional的值不为null则调用函数式接口Function,如果函数式接口返回的值为null,则抛出NullPointerException异常。
* 如果Optional的值不为null则调用函数式接口Function,并返回Optional实例,如果不为null则返回函数式接口返回的值的Optional实例。
*/
public static void useFlatMap() {
    // 如果传入的Function函数式接口为空则抛出NullPointerException异常。
    Optional<String> notNullOpt = Optional.of("小红帽");
    try {
        notNullOpt.flatMap(null);
    } catch (NullPointerException e) {
        e.printStackTrace();
    }

    // 如果Optional的值为null则返回空的Optional。
    Optional<String> isNullOpt = Optional.empty();
    Optional<String> result_1 = isNullOpt.flatMap(s -> Optional.empty() );
    System.out.println("Optional中是否有值:" + result_1.isPresent());


    // 如果Optional的值不为null则调用函数式接口Function,如果函数式接口返回的值为null,则抛出NullPointerException异常。
    try {
        Optional<Object> result_2 = notNullOpt.map(s -> null);
        System.out.println("Optional中是否有值:" + result_2.isPresent());
    } catch (NullPointerException e) {
        e.printStackTrace();
    }

    // 如果Optional的值不为null则调用函数式接口Function,并返回Optional实例,如果不为null则返回函数式接口返回的值的Optional实例。
    Optional<Object> result_3 = notNullOpt.flatMap(s ->  Optional.of("x想"));
    System.out.println("Optional中是否有值:" + result_3.isPresent() + ",值为:" + result_3.get());
}

(3)、运行结果

java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	at java.util.Optional.flatMap(Optional.java:237)
	at cn.minhat.other.OptionalTest.useFlatMap(OptionalTest.java:183)
	at cn.minhat.other.OptionalTest.main(OptionalTest.java:21)
Optional中是否有值:false
Optional中是否有值:false
Optional中是否有值:true,值为:x想

Process finished with exit code 0

6、orElse(T other)

如果Optional的值不为null则返回当前的Optional的值,否则返回other的值。

(1)、方法签名

/**
* 如果存在则返回值,否则返回other。
*
* @param other 如果没有值,则返回值,可能为空
* @return 如果存在,否则 other
*/
public T orElse(T other);

(2)、示例代码

/**
* 如果Optional的值不为null则返回当前的Optional的值,否则返回other的值。
*/
public static void useOrElse() {
    // Optional的值不为空
    Optional<String> notNullOpt = Optional.of("小红帽");
    String result_1 = notNullOpt.orElse("好好学习");
    System.out.println("Optional的值为:" + result_1);

    // Optional的值不空,返回值不为空
    Optional<String> isNullOpt = Optional.empty();
    String result_2 = isNullOpt.orElse("好好学习");
    System.out.println("Optional的值为:" + result_2);

    // Optional的值不空,返回值为空
    String result_3 = isNullOpt.orElse(null);
    System.out.println("Optional的值为:" + result_3);
}

(3)、运行结果

Optional的值为:小红帽
Optional的值为:好好学习
Optional的值为:null

Process finished with exit code 0

7、orElseGet(Supplier<? extends T> other)

如果Optional的值不为null则返回当前的Optional的值,否则返回Supplier函数式接口的值,如果函数式接口为空则抛出NullPointerException异常。

(1)、方法签名

/**
* 返回值(如果存在),否则调用 other并返回该调用的结果。
*
* @param other 一个 Supplier ,如果没有值,则返回其结果
* @return 值(如果存在)否则other.get()的结果
* @throws NullPointerException 如果值不存在且other为空
*/
public T orElseGet(Supplier<? extends T> other);

(2)、示例代码

/**
* 如果Optional的值不为null则返回当前的Optional的值,否则返回Supplier函数式接口的值,如果函数式接口为空则抛出`NullPointerException`异常。
*/
public static void useOrElseGet() {
    // Optional的值不为空,Supplier不为空
    Optional<String> notNullOpt = Optional.of("小红帽");
    System.out.println("Optional的值为:" + notNullOpt.orElseGet(() -> "小红帽"));

    // Optional的值为空,Supplier不为空
    Optional<String> isNullOpt = Optional.empty();
    System.out.println("Optional的值为:" + isNullOpt.orElseGet(() -> "小红帽"));

    // Optional的值为空,Supplier不为空,返回值为空
    System.out.println("Optional的值为:" + isNullOpt.orElseGet(() -> null));

    // Optional的值为空,Supplier为空
    System.out.println("Optional的值为:" + isNullOpt.orElseGet(null));
}

(3)、运行结果

Optional的值为:小红帽
Optional的值为:小红帽
Optional的值为:null
Exception in thread "main" java.lang.NullPointerException
	at java.util.Optional.orElseGet(Optional.java:267)
	at cn.minhat.other.OptionalTest.useOrElseGet(OptionalTest.java:242)
	at cn.minhat.other.OptionalTest.main(OptionalTest.java:24)

Process finished with exit code 1

8、orElseThrow(Supplier<? extends X> exceptionSupplier)

如果Optional的值不为null则返回当前的Optional的值,否则抛出Supplier函数式接口返回的异常,如果函数式接口为空则抛出NullPointerException异常。

(1)、方法签名

/**
* 返回包含的值(如果存在),否则抛出由提供的Supplier创建的异常。
*
* @apiNote 可以使用具有空参数列表的异常构造函数的方法引用作为Supplier。 例如, IllegalStateException::new
*
* @param <X> 要抛出的异常的类型
* @param exceptionSupplier 将返回要抛出的异常的Supplier
* @return Option的值
* @throws X 如果没有值存在
* @throws NullPointerException 如果没有值, exceptionSupplier为空
*/
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X{};

(2)、示例代码

/**
* 如果Optional的值不为null则返回当前的Optional的值,否则抛出Supplier函数式接口返回的异常,如果函数式接口为空则抛出NullPointerException异常。
*/
public static void useOrElseThrow() {
    // Optional的值不为空,Supplier不为空
    Optional<String> notNullOpt = Optional.of("小红帽");
    System.out.println("Optional的值为:" + notNullOpt.orElseThrow(RuntimeException::new));

    // Optional的值为空,Supplier不为空
    Optional<String> isNullOpt = Optional.empty();
    try {
        System.out.println("Optional的值为:" + isNullOpt.orElseThrow(RuntimeException::new));
    } catch (Exception e) {
        e.printStackTrace();
    }

    // Optional的值为空,Supplier为空
    try {
        System.out.println("Optional的值为:" + isNullOpt.orElseThrow(null));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

(3)、运行结果

Optional的值为:小红帽
java.lang.RuntimeException
	at java.util.Optional.orElseThrow(Optional.java:290)
	at cn.minhat.other.OptionalTest.useOrElseThrow(OptionalTest.java:257)
	at cn.minhat.other.OptionalTest.main(OptionalTest.java:25)
java.lang.NullPointerException
	at java.util.Optional.orElseThrow(Optional.java:290)
	at cn.minhat.other.OptionalTest.useOrElseThrow(OptionalTest.java:263)
	at cn.minhat.other.OptionalTest.main(OptionalTest.java:25)

Process finished with exit code 0

9、equals(Object obj)

指示其他某个对象是否“等于”此 Optional。 在以下情况下,另一个对象被认为是相等的:

  • 同一个Optional
  • 两个Optional的值都为null
  • 当前值通过Objects.equals()彼此“相等”

(1)、方法源码

/**
* 指示其他某个对象是否“等于”此 Optional。 在以下情况下,另一个对象被认为是相等的:
* <ul>
* 	<li>同一个Optional
* 	<li>两个Optional的值都为null
* 	<li>当前值通过Objects.equals()彼此“相等”
* </ul>
*
* @param 要进行相等测试的对象
* @return 如果另一个对象“等于”这个对象否则 false
*/
@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (!(obj instanceof Optional)) {
        return false;
    }
    Optional<?> other = (Optional<?>) obj;
    return Objects.equals(value, other.value);
}

(2)、示例代码

/**
 * 指示其他某个对象是否“等于”此 Optional。 在以下情况下,另一个对象被认为是相等的:
 * - 同一个Optional
 * - 两个Optional的值都为null
 * - 当前值通过Objects.equals()彼此“相等”
 */
public static void useEquals() {
    Optional<String> opt_1 = Optional.of("小红帽");
    Optional<String> opt_2 = opt_1;
    Optional<String> opt_3 = Optional.of("小红帽");
    Optional<String> opt_4 = Optional.empty();
    Optional<String> opt_5 = Optional.empty();
    System.out.println("opt_1.equals(opt_2):" + opt_1.equals(opt_2));
    System.out.println("opt_1.equals(null):" + opt_1.equals(null));
    System.out.println("opt_1.equals(Date):" + opt_1.equals(new Date()));
    System.out.println("opt_1.equals(opt_3):" + opt_1.equals(opt_3));
    System.out.println("opt_4.equals(opt_5):" + opt_4.equals(opt_5));
}

(3)、运行结果

opt_1.equals(opt_2):true
opt_1.equals(null):false
opt_1.equals(Date):false
opt_1.equals(opt_3):true
opt_4.equals(opt_5):true

Process finished with exit code 0

七、总结

Optional 是 Java 语言的有益补充 —— 它旨在减少代码中的 NullPointerExceptions,虽然还不能完全消除这些异常。

它也是精心设计,自然融入 Java 8 函数式支持的功能。

总的来说,这个简单而强大的类有助于创建简单、可读性更强、比对应程序错误更少的程序。