系列文章
序号 | 标题 | 文章链接 |
1 | 玩转 Java8 Stream,让你代码更高效紧凑简洁 | |
2 | 我使用 Lambda 表达式将上百行的代码精简到几行 | |
目录
- 4.1 Optional 对象创建
- 4.2 get()
- 4.3 isPresent()
- 4.4 ifPresent(Consumer<? super T> consumer)
- 4.5 filter(Predicate<? super T> predicate)
- 4.6 map(Function<? super T, ? extends U> mapper)
- 4.7 orElse(T other)
- 4.7 orElseGet(Supplier<? extends T> other)
- 4.8 orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
- 4.9 与 Stream 结合使用
一、Optional 是什么?
官方定义:
public final class Optional<T> extends Object
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
Additional methods that depend on the presence or absence of a contained value are provided, such as orElse() (return a default value if value not present) and ifPresent() (execute a block of code if the value is present).
This is a value-based class; use of identity-sensitivemin operations (including reference equality (==), identity hash code, or synchronization) on instances of Optional may have unpredictable results and should be avoided.
Optional
类,一个可包含或不包含非null值
的容器对象
。如果值存在,isPresent()
方法将返回 true 并且 get()
返回该值。
这个类还提供了其他方法,这些方法取决于它所包含值的存在与否,例如 orElse()
(如果不存在值,则返回默认值)和 ifPresent()
(如果存在值,则执行代码块)。
这是一个基于值的类,所以对于Optional实例的一些身份敏感操作(包括引用相等==,hashCode,同步)会产生无法预料的结果,应该避免使用。
二、Optional 有什么用?
- 既然 Optional 类里面包含的值可以为
null
,不言而喻,那我们就可以不用显式地进行空值检测,即我们可以不用做判空操作,很好的解决了空指针异常问题(NullPointerException
)。- Java8引入了函数式编程,而 Optional 是其中必不可少的一部分,帮助在范式中实现。结合 Stream 可以写出简洁高效的代码。
先举个栗子,输出一个员工的岗位名称,如果岗位名称为空,则输出默认值 - 实习生:
if (null != staff.getPost().getName()) {
System.out.println(staff.getPost().getName());
} else {
System.out.println("实习生");
}
以上语句有可能抛出NPE,为了健壮性,我们需要写判空:
if (null != staff) {
Post post = staff.getPost();
if (null != post) {
String name = post.getName();
if (null != name) {
System.out.println(name);
} else {
System.out.println("实习生");
}
}
}
但是写了大量的判空操作,很繁琐,代码冗余还很难维护。如果使用Optional则很简单如下:
System.out.println(
Optional.ofNullable(staff).map(Staff::getPost).map(Post::getName).orElse("实习生"));
三、Optional 源码详解
public final class Optional<T> {
// 包含一个空值的Optional容器对象
private static final Optional<?> EMPTY = new Optional<>();
// Optional容器包含的值
private final T value;
// 私有构造方法,创建一个包含空值的Optional容器对象
private Optional() {
this.value = null;
}
// 静态方法,创建一个空值的Optional容器对象
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
// 私有构造方法,创建一个包含非空值的Optional容器对象
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
// 静态方法,创建一个包含非空值的Optional容器对象
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
// 静态方法,创建一个包含可空值的Optional容器对象
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
// 获取值,如果值为null,则抛出异常
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
// 判断值是否不为null
public boolean isPresent() {
return value != null;
}
// 如果值不为null,则使用改值调用consumer函数
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
// 如果值存志,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
// 如果值存在,则对其执行调用映射函数得到新的返回值。否则返回空Optional。
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));
}
}
// 如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
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));
}
}
// 如果值存在,返回此值, 否则返回other。
public T orElse(T other) {
return value != null ? value : other;
}
// 如果值存在,返回此值, 否则调用other函数,并返回other函数的结果。
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
// 如果值存在,返回此值,否则抛出由Supplier继承的异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
}
四、Optional 类的使用
4.1 Optional 对象创建
// 创建一个空值的Optional对象
Optional<Object> emptyOptional = Optional.empty();
// 创建一个值可为空的Optional对象
Optional<Staff> staffOptional = Optional.ofNullable(staff);
// 创建一个非空值的Optional对象
Optional<Staff> staffOptional1 = Optional.of(staff);
4.2 get()
// 返回Optional容器对象中包含的值,如果值为null则抛出异常
Staff staff = staffOptional.get();
4.3 isPresent()
// 判断值是否存在
if (staffOptional.isPresent()) {
Staff staff = staffOptional.get();
}
4.4 ifPresent(Consumer<? super T> consumer)
// 如果值存在,则输出值
staffOptional.ifPresent(System.out::println);
4.5 filter(Predicate<? super T> predicate)
// 是否存在18岁的员工,如果存在,则输出她的姓名
staffOptional.filter(staff -> staff.getAge() == 18)
.ifPresent(staff -> System.out.println(staff.getName()));
4.6 map(Function<? super T, ? extends U> mapper)
// 获取员工的姓名,如果staff或name为null,输出'未知'
System.out.println(staffOptional.map(Staff::getName).orElse("未知"));
4.7 orElse(T other)
// 如果staff为null,将新生成的Staff对象赋值给staff
staff = Optional.ofNullable(staff).orElse(new Staff());
4.7 orElseGet(Supplier<? extends T> other)
// // 如果staff为null,才new出一个Staff对象,赋值给staff,它与orElse不同的是执行时机不同,orElseGet是值为空才调用other函数。
staff = Optional.ofNullable(staff).orElseGet(Staff::new);
4.8 orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
// 如果staff为null,则抛出异常
staff = Optional.ofNullable(staff).orElseThrow(() -> new NullPointerException());
4.9 与 Stream 结合使用
// 找出一个员工大于等于18岁的员工
Optional<Staff> staffOptional = staffList.stream().filter(staff -> staff.getAge() >= 18).findFirst();
if (staffOptional.isPresent()) {
Staff staff = staffOptional2.get();
}