欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Java8】Optional

程序员文章站 2022-06-06 23:38:27
...

功能

  Java8引入的java.util.Optional<T>,提供了一些优雅的方法处理null,可以减少程序中的NullPointerException

定义

  Optional<T>是一个容器对象,可以保存类型为T的空值或非空值。

声明

public final class Optional<T>
extends Object

构造方法

Optional.of(obj);   //传入值为null时,会报NullPointerException
Optional.ofNullable(obj); //传入null,返回Optional.empty();非null,返回Optional.of(obj)
Optional.empty();  //一个空的Optional实例,调用isPresent(),返回false

看起来,第二种方式是最好的。不过,既然其他两种方式都没有被置为私有,应该也有其意义:

  • 当我们非常明确传入值不为空时,可以使用第一种方式。例如:刚new出来的对象;非null的常量。
  • 不希望NullPointerException被隐藏时,也可以使用第一种方式。

最佳实践

  我们要怎么去使用Optional实例?假定我们有一个实例Optional<User> user

  • 存在即返回,无则提供默认值(orElse)
return user.orElse(UNKNOWN_USER); //而不是return user.isPresent()? user.get():null;
  • 存在即返回,无则由函数产生(orElseGet)
return user.orElseGet(() -> fetchAUserFromDatabase());
  • 存在则对它进行操作(ifPresent)
user.ifPresent(System.out::println);

//而不是下面的代码
if (user.isPresent()) {
  System.out.println(user.get());
}

map函数

   当user.isPresent()为真时,返回它的Username属性值;为假,则返回一个空集合。可以使用map函数实现。

return user.map(u -> u.getUsername()).orElse(Collections.emptyList())

//之前的做法
if(user.isPresent()) {
  return user.get().getUsername();
} else {
  return Collections.emptyList();
}

  map是可以无限级联的,比如再深一层,获得用户名的大写形式:

return user.map(u -> u.getUsername())
           .map(name -> name.toUpperCase())
           .orElse(null);

  没有Optional时的做法:

//之前的做法
User user = .....
if(user != null) {
  String name = user.getUsername();
  if(name != null) {
    return name.toUpperCase();
  } else {
    return null;
  }
} else {
  return null;
}

过滤值

  除了转换值,Optional类也提供了按条件过滤值的方法filter()。它接受一个Predicate参数,返回测试结果为true的值。如果测试结果为false,则返回一个空的Optional。示例:根据基本的电子邮箱验证来决定接受或拒绝User。

User user = new User("[email protected]","123");
Optional<User> result = Optional.ofNullable(user)
                        .filter(u -> u.getEmail() != null && u.getEmail().contains("@"));

返回异常

  Optional定义了orElseThrow(),它会在对象为空的时候抛出异常,而不是返回备选的值:

Optional.ofNullable(user).orElseThrow( () -> new IllegalArgumentException() );

  这里,如果user值为null,会抛出IllegalArgumentException。这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出NullPointerException

杂谈

  • Optional没有继承Serializable,所以,它不可以直接做为类的属性。如果需要,可以这样写:
private Address address;

public Optional<Address> getAddress(){
    return Optional.ofNullable(address);
}
  • Optional尽量不要作为方法参数,会让代码变的复杂,没有必要。可以通过重载来处理。
  • Optional主要用作返回类型。在获取到这个类型的实例后,如果它有值,你可以取得这个值,否则可以设置替代行为。
  • Optional类有一个非常有用的用例,就是将其与流(Java9支持)或者其它返回Optional的方法结合,完成更复杂的操作。

参考资料:https://blog.csdn.net/hj7jay/article/details/52459334
参考资料:https://www.cnblogs.com/zhangboyu/p/7580262.html
参考资料:https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

上一篇: Java8 Optional

下一篇: java8 Optional