Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
示例:

  1. import java.util.Optional;
  2. public class Java8Tester {
  3. public static void main(String args[]){
  4. Java8Tester java8Tester = new Java8Tester();
  5. Integer value1 = null;
  6. Integer value2 = new Integer(10);
  7. // Optional.ofNullable - 允许传递为 null 参数
  8. Optional<Integer> a = Optional.ofNullable(value1);
  9. // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
  10. Optional<Integer> b = Optional.of(value2);
  11. System.out.println(java8Tester.sum(a,b));
  12. }
  13. public Integer sum(Optional<Integer> a, Optional<Integer> b){
  14. // Optional.isPresent - 判断值是否存在
  15. System.out.println("第一个参数值存在: " + a.isPresent());
  16. System.out.println("第二个参数值存在: " + b.isPresent());
  17. // Optional.orElse - 如果值存在,返回它,否则返回默认值
  18. Integer value1 = a.orElse(new Integer(0));
  19. //Optional.get - 获取值,值需要存在
  20. Integer value2 = b.get();
  21. return value1 + value2;
  22. }
  23. }

测试实体User

  1. @Data
  2. @Accessors(chain = true)
  3. @AllArgsConstructor
  4. @NoArgsConstructor
  5. public class User {
  6. private String id;
  7. private String name;
  8. private Integer age;
  9. private LocalDate birthday;
  10. public User(String name) {
  11. this.name = name;
  12. }
  13. }

测试方法

private static User createUser(String id) {
        log.info("执行了生成方法:::id===>{}", id);
        return new User(id, "小米" + id, 18, LocalDate.now());
    }

    private static User getNull() {
        return null;
    }

一、Optional 常用方法及使用示例

1、静态方法

empty(),of(T value),ofNullable(T value)

1.1、of(T value),

  • 方法作用: 为指定的值创建一个指定非 null 值的 Optional。
  • 方法描述: of 方法通过工厂方法创建 Optional 实例,需要注意的是传入的参数不能为 null,否则抛出 NullPointerException。
  • 返回类型: Optional
public static void testOf() {
        // 传入正常值,正常返回一个 Optional 对象
        Optional<User> optional1 = Optional.of(createUser("1"));
        log.info("{}", optional1);

        // 传入参数为 null,抛出 NullPointerException.
        Optional<User> optional2 = Optional.of(getNull());
        log.info("{}", optional2);
    }

可以看到传入正常参数正常返回 Optional 对象,传入 null 参数返回 NullPointerException 异常。
image.png

1.2、empty()

源码:

public final class Optional<T> {
    //省略....
    private static final Optional<?> EMPTY = new Optional<>();
    private Optional() {
        this.value = null;
    }
    //省略...
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
}

empty()的作用就是返回EMPTY对象。

1.3、ofNullable()

  • 方法作用: 为指定的值创建一个 Optional 对象,如果指定的参数为 null,不抛出异常,直接则返回一个空的 Optional 对象。
  • 方法描述: ofNullable 方法是和 of 方式一样,都是用于创建 Optional 对象,只是传入的参数 null 时,会返回一个EMPTY对象,而不会抛出 NullPointerException 异常。
  • 返回类型: Optional
public static void testOfNullable() {
        // 传入正常值,正常返回一个 Optional 对象
        Optional<User> optional1 = Optional.ofNullable(createUser("1"));
        log.info("{}", optional1);
        // 传入 null 参数,正常返回 Optional 对象
        Optional<User> optional2 = Optional.ofNullable(null);
        log.info("{}", optional2);
    }

可以观察到正常传入值和传入 null 值时,都没有抛出异常。
image.png
该方法在开发中使用最多的

2、对象方法

  • orElse(T other)
  • orElseGet(Supplier other)
  • orElseThrow(Supplier exceptionSupplier)

这三个函数都是在构造函数传入的value值为null时,进行调用的。

2.1、orElse()

  • 方法作用: 如果该值存在就直接返回, 否则返回指定的其它值。
  • 方法描述: orElse 方法实现很简单,就是使用三目表达式对传入的参数值进行 null 验证,即 value != null ? value : other; 如果为 null 则返回 true,否则返回 false。
  • 返回类型: T

    2.2、对象方法 orElseGet()

  • 方法作用: 如果该值存在就返回值,否则触发 other,并返回 other 调用的结果。

  • 方法描述: orElseGet 方法和 orElse 方法类似,都是在 Optional 值为空时,返回一个默认操作,只不过 orElse 返回的是默认值,而 orElseGet 是执行 lambda 表达式,然后返回 lambda 表达式执行后的结果。
  • 返回类型: T
public static void testOrElseAndOrElseGet() {
        //传入一个空值的情况
        User user1 = getNullUser();
        User user2 = getNullUser();
        user1 = Optional.ofNullable(user1).orElse(createUser("1"));
        user2 = Optional.ofNullable(user2).orElseGet(() -> createUser("2"));
        log.info("当值为null时,orElse" + JSON.toJSONString(user1));
        log.info("当值为null时,orElseGet" + JSON.toJSONString(user2));
        //传入不为空值的情况
        User user3 = createUser("10086");
        User user4 = createUser("10000");
        user3 = Optional.ofNullable(user3).orElse(createUser("3"));
        user4 = Optional.ofNullable(user4).orElseGet(() -> createUser("4"));

        log.info("当值不为null时,orElse" + JSON.toJSONString(user3));
        log.info("当值不为null时,orElseGet" + JSON.toJSONString(user4));
    }

执行结果如下:
image.png
结论:
当 Optional 值为空时:
orElse()和orElseGet()都会返回执行的结果

当 Optional 值不为空时:
orElse()会执行其中的方法,但是orElseGet()不会执行

2.3、对象方法 orElseThrow()

  • 方法作用: 如果 Optional 存在该值,返回包含的值,否则抛出由 Supplier 继承的异常。
  • 方法描述: orElseThrow 方法其实就是判断创建 Optional 时传入的参数是否为 null,如果是非 null 则返回传入的值,否则抛出 异常。
  • 返回类型: T
public static void testOrElseThrow(){
        // 传入 null 参数,获取一个 Optional 对象,并使用 orElseThrow 方法
        User user2 = getNull();
        User object2 = Optional.ofNullable(user2).orElseThrow(() -> new RuntimeException("参数为空===>抛出异常"));
        log.info("输出的值为:" + object2);
    }

可以观察到,当创建 Optional 时如果传入的参数为空则执行 Lambda 表达式代码逻辑后抛出异常信息,否则返回传入的参数值。
image.png

3、转换值方法

  • map(Function mapper)
  • flatMap(Function> mapper)

这两个函数,在函数体上没什么区别。
唯一区别的就是入参
map的入参类型为Function<? super T, ? extends U>
flapMap的入参类型为Function<? super T, Optional>

3.1、map()

  • 方法作用: 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。
  • 方法描述:

map 方法主要用于获取某个对象中的某个属性值的 Optional 对象时使用。
map 方法调用时,首先验证传入的映射函数是否为空,如果为空则抛出异常。
然后,再检测 Optional 的 value 是否为空,如果是,则返回一个空 value 的 Optional 对象。
如果传入的映射函数和 Optinal 的 value 都不为空,则返回一个带 value 对象属性的 Optional 对象。

  • 返回类型: Optional
public static void testMap() {
        // 创建 map 对象
        Map<String, User> userMap = new HashMap<>();
        userMap.put("user1", createUser("1"));
        userMap.put("user2", getNull());

        //String name1 = Optional.ofNullable(userMap.get("user1")).map(value -> value.getName()).get();
        String name1 = Optional.ofNullable(userMap.get("user1")).map(User::getName).get();
        log.info("获取值===>{}", name1);
        // 传入 Map 对象参数,获取一个 Optional 对象,获取 user2 属性
        //String name2 = Optional.ofNullable(userMap.get("user2")).map(value -> value.getName()).get();
        String name2 = Optional.of(Optional.ofNullable(userMap.get("user2")).orElse(createUser("0000"))).map(User::getName).get();
        log.info("获取值===>{}", name2);
    }

image.png

通过上面两个示例观察到,通过 Optional 对象的 map 方法能够获取映射对象中的属,创建 Optional 对象,并以此属性充当 Optional 的值,结合 orElse 方法,如果获取的属性的值为空,则设置默认值。

3.2、flatMap()

  • 方法作用: 如果值存在,返回基于 Optional 包含的映射方法的值,否则返回一个空的 Optional。
  • 方法描述:

flatMap 方法和 map 方法类似,唯一的不同点就是
map 方法会对返回的值进行 Optional 封装,
flatMap需要手动执行 Optional.of 或 Optional.ofNullable 方法对值进行封装。

  • 返回类型: Optional

    public static void testFlatMap() {
          // 创建 map 对象
          Map<String, String> userMap = new HashMap<>();
          userMap.put("name", "javaCoder");
          userMap.put("sex", "男");
    
          // 传入 Map 对象参数,获取一个 Optional 对象
          Optional<Map<String, String>> optional1 = Optional.of(userMap);
    
          // 使用 Optional 的 flatMap 方法,获取 Map 中的 name 属性
          // 然后通过获取的值手动创建一个新的 Optional 对象
          Optional<String> optional2 = optional1.flatMap(value -> Optional.ofNullable(value.get("name")));
    
          // 获取 Optional 的 value
          log.info("获取的 Optional 的值:" + optional2.get());
      }
    

    image.png

根据结果观察,可以看到 flatMap 和 map 方法没有什么区别,但是仔细看,代码中调用 flatMap 后,需要手动执行 of 或 ofNullable 方法创建了 Optional 对象。

4、判断方法

  • isPresent()
  • ifPresent(Consumer consumer)

isPresent即判断value值是否为空,
ifPresent就是在value值不为空时,做一些操作

4.1、isPresent()

  • 方法作用: 如果值存在则方法会返回 true,否则返回 false。
  • 方法描述: 该方法其实就是用于判断创建 Optional 时传入参数的值是否为空,实现代码就简单一行,即 value != null 所以如果不为空则返回 true,否则返回 false。
  • 返回类型: boolean

    public static void testIsPresent() {
          // 传入正常值,正常返回一个 Optional 对象,并使用 isPresent 方法
          Optional<User> optional1 = Optional.of(createUser("1"));
          log.info("传入正常值返回:" + optional1.isPresent());
    
          // 传入参数为 null 生成一个 Optional 对象,并使用 isPresent 方法
          Optional<User> optional2 = Optional.ofNullable(getNull());
          log.info("传入 null 值返回:" + optional2.isPresent());
      }
    

可以看到传入正常参数时调用 Optional 对象的 isPresent 方法时返回 true,传入 null 参数返回 false。
image.png

4.2、对象方法 get()

  • 方法作用: 如果 Optional 有值则将其返回,否则抛出 NoSuchElementException 异常。
  • 方法描述: get 方法内部实现其实就是判断 Otpional 对象中的 value 属性是否为 null,如果是就抛出 NoSuchElementException 异常,否则返回这个 value 值。
  • 返回类型: T

可以观察到传入正常值的 Optional 调用 get 方法正常输出值,通过空的 optional 对象使用 get 方法获取值时,抛出 NoSuchElementException 异常:
image.png

4.2、对象方法 ifPresent()

  • 方法作用: 如果值存在则使用该值调用 consumer , 否则不做任何事情。
  • 方法描述: 该方法 ifPresent(Consumer<? super T> consumer) 中参数接收的是 Consumer 类,它包含一个接口方法 accept(),该方法能够对传入的值进行处理,但不会返回结果。这里传入参数可以传入 Lamdda 表达式或 Consumer 对象及实现 Consumer 接口的类的对象。
  • 返回类型: void
    public static void testIfPresent() {
          // 创建 Optional 对象,然后调用 Optional 对象的 ifPresent 方法,传入 Lambda 表达式
          Optional<User> user1 = Optional.of(createUser("1"));
          Consumer<User> consumer = (v) -> {
              log.info("{}的年龄是{},生日是:{}", v.getName(), v.getAge(), v.getBirthday());
          };
          user1.ifPresent((value) -> log.info("直接实现:{}",value));
          //传入实现 Consumer 匿名内部类
          user1.ifPresent(consumer);
      }
    
    可以观察到,调用 ifPresent 使用 lambda 或者内部匿名类方法,都是为了再执行 Optional 对象的 ifPresent 方法时,执行一段代码逻辑。

image.png

5、过滤方法

5.1、filter(Predicate predicate)

  • 方法作用: 如果有值并且满足断言条件返回包含该值的 Optional,否则返回空Optional.EMPTY。
  • 方法描述: filter 方法通过传入的限定条件对 Optional 实例的值进行过滤,如果 Optional 值不为空且满足限定条件就返回包含值的 Optional,否则返回空的 Optional。这里设置的限定条件需要使用实现了 Predicate 接口的 lambda 表达式来进行配置。
  • 返回类型: Optional
public static void testFilter() {
        // 创建一个测试的 Optional 对象
        Optional<User> optional = Optional.of(createUser("100"));

        // 调用 Optional 的 filter 方法,设置一个满足的条件,然后观察获取的 Optional 对象值是否为空
        optional = optional.filter((value) -> value.getAge() > 2);
        log.info("Optional 的值不为空::" + optional.isPresent());

        // 调用 Optional 的 filter 方法,设置一个不满足的条件,然后观察获取的 Optional 对象值是否为空
        optional = optional.filter((value) -> value.getAge() < 2);
        log.info("Optional 的值不为空::" + optional.isPresent());
    }

image.png

根据结果可以观察到,可以通过 filter 设置一个条件来判断 Optional 的值,如果满足条件就返回带值的 Optional,否则返回空的 Optional。

二、Optional 常用示例组合

Optional 是个容器,它可用保存类型的 T 的值,即使 T 为 null 也可以使用 Optional 存储,这样我就不用显示进行空值检测,防止空指针异常。
在实际使用中这些方法常常组合使用。且很多方法也常与 Lambda 表达式结合,获取我们想要的结果的值。

对集合中的对象属性进行过滤

 // 创建一个测试的用户集合
        List<User> userList = new ArrayList<>();

        // 创建几个测试用户
        User user1 = new User("abc");
        User user2 = new User("efg");
        User user3 = null;

        // 将用户加入集合
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);

        // 创建用于存储姓名的集合
        List<String> nameList = new ArrayList();
        // 循环用户列表获取用户信息,值获取不为空且用户以 a 开头的姓名,
        // 如果不符合条件就设置默认值,最后将符合条件的用户姓名加入姓名集合
        for (User user : userList) {
            nameList.add(Optional.ofNullable(user).map(User::getName).filter(value -> value.startsWith("a")).orElse("未填写"));
        }

        // 输出名字集合中的值
        System.out.println("通过 Optional 过滤的集合输出:");
        nameList.stream().forEach(System.out::println);

image.png
通过上面,可以观察到,使用 Optional 有时候可以很方便的过滤一些属性,而且它的方法可以通过链式调用,方法间相互组合使用,使我们用少量的代码就能完成复杂的逻辑。

判空写法

if(user!=null){
    dosomething(user);
}

//Java8
 Optional.ofNullable(user)
    .ifPresent(u->{
        dosomething(u);
});

附录:

参考:
https://mp.weixin.qq.com/s/TOtHLm6k0VjsQeRrIVB3Hw