【Java8】Optional

功能

  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

猜你喜欢

转载自blog.csdn.net/gnd15732625435/article/details/80717687