Optional 类
作用
首次出现在 Google 的 Guava 类库中,在 Java 8 中引入,用于解决 NullPointerException
问题,避免代码中频繁的 null 检查。
数据结构
Optional 类是对原有数据类型的一个封装。如果原有变量不存在,Optional 类会通过 Optional.empty()
方法返回空的 Optional 对象,避免返回 null 值。
使用
创建
创建空 Optional:
Optional<Car> option = Optional.empty();
创建非空 Optional:
Optional<Car> option = Optional.of(myCar);
创建可以包含 null 值的 Optional:
Optional<Car> option = Optional.ofNullable(yourCar);
判断值/获取值
判断是否存在值 isPresent()
,获取原数据 get()
:
if(option.isPresent()) {
System.out.println(option.get());
}
ifPresent
会接收一个消费者类型函数式接口的实现,如果 Optional 实例中的值不为空,则调用 Cosumer 的 accept 方法对 value 进行消费,若值为空则不做处理:
public void ifPresent(Consumer<? super T> action) {
if(value != null) {
action.accept(value);
}
}
使用 ifPresent
来代替 isPresent()
与 get()
方法:
optional.isPresent((val) -> System.out.println(val));
orElse()
: 同 get()
方法,在值为空时返回默认值
Optional<Car> option = Optional.empty();
System.out.println(option.orElse("MINI COOPER");
orElseGet()
:接收一个 Supplier
类型的 函数式接口 实现,功能同 orElse ()
String Optional.empty().orElseGet(() -> "Default");
orElseThrow()
:接收 函数式接口, 如无值抛出异常
map
:使用 Lambda 表达式对 Optional 对象进行操作,map 函数返回前会封装为 Optional 对象。
使用 Stream 的 map:
public Optional<Employee> findEmployeeById(int id) {
// do something
}
public List<Employee> findEmplogyeeByIds(List<Integer> ids) {
return ids.stream()
.map(this::findEmployeeById)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
}
使用 Optional 的 map:
public List<Employee> findEmplogyeeByIds(List<Integer> ids) {
return ids.stream()
.map(this::findEmployeeById)
.flatMap(optional -> optional.map(Stream::of)
.orElseGet(Stream::empty))
.collect(Collector.toList());
}
flatMap
:与 map
类似,区别在与 flatMap 的返回值必须是 Optional,不会像 map
那样进行封装。
filter
: 对 Optional 对象进行校验,如果满足条件返回原对象,如果不满足返回空 Optional 对象。
Optional<String> longName = username.filter((value) -> value.length() > 2);
System.out.println(longName.orElse("The name is less than 2 characters"));
获取 optional 对象的属性值
Optional<Person> person = getPerson(index);
return person.map(Person::getName).orElse("unknown");
场景
使用 Optional
的目的是为了上开发者不要忘记非空检查。
Optional 类的缺点有:
- 不能避免 NPE 问题,只是将异常转化为
NoSuchElementException
- 更难理解
- 效率较低
阿里《Java开发手册》建议对于级联调用 obj.getA().getB().getC()
使用 Optional 类来防止 NPE 问题。如果在不使用链式语法的场景,使用 null 来判断效率更高。
尽量避免将 Optional 用于类属性,方法参数与集合元素中,因为完全可以使用 null, 违反了使用 Optional 类的初衷。