参考的博客写在前面吧,感觉没他们写的好
【java8新特性】Optional详解 - 简书 (jianshu.com)
理解、学习与使用 Java 中的 Optional - 张伯雨 - 博客园 (cnblogs.com)
一、为什么要引入Optional
下面这代码,我们访问任何对象或属性,都有可能因为某个对象为null
导致NullPointerException
String result = school.getStudent().getA();
为了解决NullPointException
(NPE)问题,一般的我们采用逐个判断是否为null
再继续下面的业务逻辑,如果需要判断的对象很多,代码看起来很多,很冗余。如下:
原先的避免NPE
的方式
// 判断每一层是否为空
if(school==null){
result = "error";
}else if(school.getStudent()==null){
result = "error";
}else if(school.getStudent().getA()==null){
result = "error";
}else {
result = school.getStudent().getA();
}
System.out.println(result);
使用Optional
的方式
//直接构造Optional并返回想要的结果
String result = Optional.ofNullable(school)
.map(School::getStudent)
.map(Student::getA)
.orElse("error");
System.out.println(result);
对比以上两种方式,可以明显的看出使用Optional的代码更加简洁,不罗嗦,在orElse
中可以直接将特殊情况返回,下面介绍Optional
的具体用法。
二、Optional的使用
先看看Optional的部分源码:
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
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
的构造函数都是私有,因此类外部不能显示的使用new Optional()
的方式来创建Optional
对象,但是Optional
类提供了三个静态方法来创建Optional
对象,示例如下:
empty()
空的Optional
对象
of(T value)
非空的Optional
对象
ofNullable(T value)
允许空的Optional
对象
Optional<String> optStr = Optional.empty(); // 空
Student student = new Student();
Optional<Student> optStudent = Optional.of(student); // 非空
Optional<Student> optClass = Optional.ofNullable(student);// 可以空
构建了Optional
对象,下面来看看怎么使用Optional
对象的接口,直接推荐两种常用的使用方式:
第一种是使用orElse()
接口,如果不为空,直接返回结果,为空返回orElse()
中的内容。看看源码先:
public T orElse(T other) {
return value != null ? value : other;
}
再来看看orElse()
的例子,将str包装成Optional
对象后,通过orElse()
返回值。
String str = "hello";
String str1 = Optional.ofNullable(str).orElse("unknown");
第二种是使用ifPresent()
接口,不为空则直接执行ifpresent()
内的函数,省去判空的步骤。看看源码先:
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
源码内提到ifPresent()
方法接受一个Consumer对象(消费函数),如果包装对象的值非空,运行Consumer对象的accept()方法,(我的理解就是一个无返回值的函数而已),看看栗子:
Optional.ofNullable(student)
.ifPresent( u -> System.out.println("The student name is : " + u.getName()));
三、Optional的其他方法列举
-
get()
方法 直接放回包装对象的实际值,为null抛出异常
-
isPresent()
方法 判断包装对象是否为空
特别说明的是,
get()
方法并没有直接对空对象有所处理,所以直接使用,仍然会有NPE
问题,于是,就有人想到:那我先用isPresent()
先判空,再取值不就好了,于是就产生了如下的憨憨的代码:Optional<Student> studentOpt = Optional.ofNullable(student); if(isPresent(studentOpt)){ String str = student.get(); }else{ String str = "unknown"; }
上面的代码违背了
Optional
的初衷,应使用orElse()
方法改为如下:String str = Optional.ofNullable(student).orElse("unknown");
-
map()
方法 将Optional中的包装对象经过函数运算后,并包装成新的
Optional
对象Optional<String> nameOpt = Optional.ofNullable(student).map(u -> u.getName());
或写成下面的格式,更加简洁
Optional<String> nameOpt = Optional.ofNullable(student).map(Student::getName);
map()
链式调用,配合上orElse()
就完成了文初的效果:String result = Optional.ofNullable(school) .map(School::getStudent) .map(Student::getA) .orElse("error"); System.out.println(result);