# 简介
Optional
类的引入很好的解决空指针异常。它是一个可以为 null
的容器对象, Optional
本身没有引入新技术,你可以把它看作对象的包装类,通过将对象封装在 Optional
中,可以省去大量空指针检查。
相关的方法可以快速阅读菜鸟教程。这里大致提一些相关的行为:
- 获取
Optional
里的值,如果该值为空,返回默认值(可以指定默认值,有点像HashMap
中的getOrDefault
) - 检测
Optional
里的值,(ifPresent
方法接收Consumer
接口,来对值进行操作) - 构造器私有,通过其他方法(静态)检测要构造对象所传入的对象是否为
null
,来选择调用构造器。
# 入门
举例来说,一个人可能有车也可能没有,那么 Person
类内部 car
变量就不应该声明为 Car
,当变量存在时, Optional
类只是对 Car
的简单封装。变量不存在时,会使用 Optional.empty()
方法返回空的 Optional
对象。如下所示:
但是 null
引用和 Optional.empty()
有什么本质区别?从语义上,它们可以当成一回事儿,但实际上差别非常大:如果尝试解引用一个 null
,一定会触发 NullPointerException
,不过使用 Optional.empty()
是一个有效对象。
# 创建对象
这里有 empty(),of(),ofNullable()
三个静态方法,都可以用来创建 Optional
对象,再次强调, Optional
的构造器是私有的。
public static<T> Optional<T> empty() { | |
@SuppressWarnings("unchecked") | |
Optional<T> t = (Optional<T>) EMPTY; | |
return t; | |
} | |
public static <T> Optional<T> of(T value) { | |
return new Optional<>(value); | |
} | |
public static <T> Optional<T> ofNullable(T value) { | |
return value == null ? empty() : of(value); | |
} |
这里要说明的是, Optional
有一个 EMPTY
的静态属性。
private static final Optional<?> EMPTY = new Optional<>(); |
Optional
是不对外提供对 value==null
时修改 value
的方法的,因为 ifPresent
会进行 null
值检测
public void ifPresent(Consumer<? super T> consumer) { | |
if (value != null) | |
consumer.accept(value); | |
} |
所以一个空的 Optional
就永远不会被加入新的值(因为无法修改),这也就意味着,所有的空的 Optional
都可以指向同一个空的 Optional
,这就是 EMPTY
。
# 其他方法
# map
源码:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { | |
Objects.requireNonNull(mapper); | |
if (!isPresent()) | |
return empty(); | |
else { | |
return Optional.ofNullable(mapper.apply(value)); | |
} | |
} |
它和 ifPresent
的区别在于, map
接收的时 Function
接口,存在返回值, map
会将 apply
的返回值封装在一个新的 Optional
中。
//map 方法执行传入的 lambda 表达式参数对 Optional 实例的值进行修改。 | |
// 为 lambda 表达式的返回值创建新的 Optional 实例作为 map 方法的返回值。 | |
Optional<String> name = Optional.of("abc"); | |
Optional<String> upperName = name.map((value) -> value.toUpperCase()); | |
System.out.println(upperName.orElse("No value found")); | |
// 输出:ABC |
# flatMap
源码:
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { | |
Objects.requireNonNull(mapper); | |
if (!isPresent()) | |
return empty(); | |
else { | |
return Objects.requireNonNull(mapper.apply(value)); | |
} | |
} |
可以看到,它和 map
的差别就是返回语句, flatmap
只是对 apply
函数返回值进行空值判断,而不将它封装在 Optional
中。但是,从函数定义可以看到, flatMap
其实返回的还是一个 Optional
,所以 mapper.apply
必须返回 Optional
。
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase())); | |
System.out.println(upperName.orElse("No value found"));// 输出 SANAULLA |
# fliter
filter
方法通过传入限定条件对 Optional
实例的值进行过滤。如果有值并且满足断言条件返回包含该值的 Optional
,否则返回空 Optional
。要加入判定条件,从这里可以知道, fliter
应该实现 Predicate
接口(断定型接口)。
public Optional<T> filter(Predicate<? super T> predicate) { | |
Objects.requireNonNull(predicate); | |
if (!isPresent()) // 如果为空 | |
return this; | |
else | |
return predicate.test(value) ? this : empty(); | |
} |
# 参考
菜鸟教程:https://www.runoob.com/java/java8-optional-class.html
Java 全栈知识体系:https://pdai.tech/md/java/java8/java8-optional.html