带你看懂Optional

概述

  • 1、JDK8最大的一个亮点就是引入了Optional类来解决NPE(NullPointerException)
  • 2、阿里开发手册上也推荐使用Optional类来防止NPE
  • 3、综上所述,解决NPE正是Optional类的功能,也是JDK8的一份亮点

Optional预览

  • 1、Optional类的声明
    • 1)被声明为final,即不可被继承
    • 2)使用泛型T,即指定Optional所包含对象的类型
    public final class Optional<T>
  • 2、Optional类的重要属性
    • 1)final类型的value,正是Optional包含对象,其中的T为创建Optional时通过泛型指定的类型
    • 2)全局静态常量EMPTY,调用的是Optional类的无参构造,其中代表value置为空
    private final T value;

	private static final Optional<?> EMPTY = new Optional<>();
  • 3、Optional类的构造方法
    • 可以看出,Optional的两个构造方法均被声明为private——代表外界不可通过new创建Optional对象,即一般在其内部自身使用
    private Optional() {
        this.value = null;
    }

    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

Optional初探——API

Methods Params Return Purpose Theory Frequency
empty() Optional<T> 将Optional的value置空 将全局静态常量EMPTY强转为对应的T类型Optional,之后进行返回 occasional
of() T类型变量 Optional<T> 创建一个包含value的Optional对象 调用Optional有参构造方法,将传递的变量赋给value often
ofNullable() T类型变量 Optional<T> 创建一个包含value的Optional对象 先判断value是否为空
value为空,直接调用empty方法返回空Optional对象
value非空,调用of方法返回一个非空包含value的Optional对象
always
get() T类型变量 获取Optional中的value
注意:一般需要先调用isPresent判断value非空
当前value为空,则抛出NoSuchElementException
否则直接返回value
occasional
isPresent 布尔型变量 判断Optional中的value是否非空 直接判断value是否非空 occasional
ifPresent Consumer消费型接口 对Optional中的value进行指定action 当value非空,对value进行指定action usual
filter Predicate断言型接口 Optional<T> 对Optional中的value进行指定test 调用Objects工具类对传入的断言型接口进行非空校验
调用isPresent方法,当value为空,直接返回当前Optional对象
当value非空,对value进行指定test,断言成功返回当前Optional对象,断言失败调用empty方法返回空Optional对象
often
map Function函数型接口 Optional<U> 对Optional中的value进行指定apply 调用Objects工具类对传入的函数型接口进行非空校验
调用isPresent方法,当value为空,直接调用empty方法返回空Optional对象
当value非空,对value进行指定apply,之后调用ofNullable方法对结果封装为新Optional
usual
flatMap Function函数型接口 Optional<U> 对Optional中的value进行指定apply
与map类似,但是它不会对结果进行Optional再封装
调用Objects工具类判断传入的函数型接口非空
调用isPresent方法,当value为空,直接调用empty方法返回空Optional对象
当value非空,对value进行指定apply,之后调用Objects工具类对结果进行非空校验
usual
orElse T类型变量 T类型变量 返回Optional中的value,其中value为空则返回传递的变量 判断Optional中value是否为空
value非空则返回value
value为空则返回传递的T类型变量
usual
orElseGet Supplier
供给型接口
T类型变量 返回Optional中的value,其中value为空则返回Supplier生产的T类型变量 判断Optional中value是否非空
value非空则返回value
value为空则对通过Supplier的get方法生产一个T类型变量返回
usual
orElseThrow Supplier
供给型接口
T类型变量 返回Optional中的value,其中value为空则抛出Supplier生产的异常消息 判断Optional中value是否非空
value非空则返回value
value为空则对通过Supplier的get方法生产一个异常消息
occasional

Optional深究——Demo

注:此处只研究经常使用的方法,其他的方法也不难理解。

  • 一般都通过ofNullable方法来创建Optional,因为这样既可以接收非Null,又可以接收Null
  • 一般都通过map方法来代替非空判断之后的getter操作
  • 一般都通过orElse方法来获取最后的值,其中一般传入null即可
package com.gezq.optionaldemos;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Optional;

/**
 * Desc: 简单测试Optional
 *
 * @author gezq0714
 * @version MyDemo:1.0.0
 * @email ge051799qi@163.com
 * @date 2021/10/1 - 20:49
 * @since MyDemo:1.0.0
 */
public class Demo {
    public static void main(String[] args) {
        // 假设User是数据库中查询出的一个对象,我们想要获取的是skillName
        User user = new User("gezq", "123456", new Skill("sing", Optional.of("you like sing")));
        // 一般操作
        String skillName1 = null;
        // 1、判断user非空
        if (user != null) {
            // 2、获取skill
            final Skill skill = user.getSkill();
            // 3、判断skill非空
            if (skill != null) {
                // 4、获取skillName
                skillName1 = skill.getSkillName();
            }
        }

        // 使用Optional————使用map获取普通属性的值
        final String skillName2 = Optional.ofNullable(user).map(User::getSkill).map(Skill::getSkillName).orElse(null);
        // 使用Optional——使用flatMap获取被Optional包装过的属性的值
        final String skillIntroduction = Optional.ofNullable(user).map(User::getSkill).flatMap(Skill::getIntroduction).orElse(null);

        System.out.println("一般操作获取skillName:" + skillName1);
        System.out.println("使用Optional获取skillName:" + skillName2);
        System.out.println("使用Optional获取skillIntroduction:" + skillIntroduction);
        /*
            输出结果如下所示:
            一般操作获取skillName:sing
            使用Optional获取skillName:sing
            使用Optional获取skillIntroduction:you like sing
         */
    }

}

@AllArgsConstructor
@NoArgsConstructor
@Data
class User {
    private String username;
    private String password;
    private Skill skill;
}

@AllArgsConstructor
@NoArgsConstructor
@Data
class Skill {
    private String skillName;
    private Optional<String> introduction;
}

上一篇:Ribbon的负载均衡源码


下一篇:Java 8 新增的 Optional