Optional源码解析
1.成员变量
/**
* Common instance for {@code empty()}.
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;
1.1 EMPTY做为一个空值的常量用于静态创建一个空的Optional对象
1.2 value用来存储Optional对象中实际的值
2.构造方法
/**
* Constructs an empty instance.
*
* @implNote Generally only one empty instance, {@link Optional#EMPTY},
* should exist per VM.
*/
private Optional() {
this.value = null;
}
2.1 第一个私有的无参构造方法,外界无法访问使用
/**
* Returns an empty {@code Optional} instance. No value is present for this
* Optional.
*
* @apiNote Though it may be tempting to do so, avoid testing if an object
* is empty by comparing with {@code ==} against instances returned by
* {@code Option.empty()}. There is no guarantee that it is a singleton.
* Instead, use {@link #isPresent()}.
*
* @param <T> Type of the non-existent value
* @return an empty {@code Optional}
*/
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
2.2 静态方法empty会返回EMPTY常量的Optional对象,里面的value值为空
/**
* Constructs an instance with the value present.
*
* @param value the non-null value to be present
* @throws NullPointerException if value is null
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
2.3 私有的有参构造,外界无法访问,提供给本类的静态方法,用于创建value有值的Optional对象,注意此处调用了 Objects.requireNonNull方法,也就意为着如果此时传入的value值为空,会抛出一个空指针异常。
3.方法说明
3.1 of和ofNullable方法
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);
}
这两个方法都会使用传入的value调用有参构造,不过如果value为null的时候,of方法会抛出空指针异常,而ofNullable方法会判断value为null后,返回空的Optional对象,所以一般为了安全性,我们都是使用后面一个方法。
3.2 get方法
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
这是获取对象中value值的方法,可以看到,如果value是一个null值,此时会抛出一个异常。
3.3 isPresent
public boolean isPresent() {
return value != null;
}
此方法返回对象中value值是否为null的判断,一般搭配上面一个get方法使用,先判断是否为空,不为空的话再调用get方法获取value值。
3.4 ifPresent
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
此方法会先判断value是否为空,为空的话,则没有任何操作,不为空的话,则用传入的函数消费value值。

此处可看到o2里面有值,所以被消费了。
3.5 filter
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
filter会先判断传入的predicate 断言是否为空,为空的话则抛出空指针异常,不为空的话接着判断value值是否为空,为空,则直接返回这个空的Optional对象,不为空接着用断言测试value值,通过返回这个对象,不通过则调用empty方法,返回一个value为空的Optional对象。
public static void main(String[] args) {
Optional<String> o1 = Optional.ofNullable(null);
Optional<String> o2 = Optional.ofNullable("hello world");
/* 断言为空 */
try {
Optional<String> filter1 = o2.filter(null);
System.out.println("第一个"+filter1.isPresent());
} catch (Exception e) {
e.printStackTrace();
}
/* value为空 */
Optional<String> filter2 = o1.filter(StringUtils::isEmpty);
System.out.println("第二个"+filter2.isPresent());
System.out.println("value为空,返回的就是此时的空对象"+ (o1 == filter2));
/* 断言不通过 */
Optional<String> filter3 = o2.filter(StringUtils::isEmpty);
System.out.println("第三个"+filter3.isPresent());
/* 断言通过 */
Optional<String> filter4 = o2.filter(StringUtils::isNotEmpty);
System.out.println("第四个"+filter4.isPresent());
System.out.println("value为空,返回的就是此时的空对象"+ (o2 == filter4));
}
运行代码得到

此时可以得知
1:断言为空,报空指针异常
2:value为空会返回传入的空对象
3:断言不通过,会返回一个新的空对象
4:断言通过,返回传入的对象
3.6 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));
}
}
map方法也是先判断传入的函数是否为空,然后判断value是否为空,最后将函数应用于value值,并返回应用转化完后的值生成的Optional对象。
public static void main(String[] args) {
Optional<String> o1 = Optional.ofNullable(null);
Optional<String> o2 = Optional.ofNullable("hello world");
/* 应用为空 */
try {
Optional<String> map1 = o2.map(null);
System.out.println("第一个"+map1.isPresent());
} catch (Exception e) {
e.printStackTrace();
}
/* value为空 */
Optional<Integer> map2 = o1.map(String::length);
System.out.println("第二个"+map2.isPresent());
/* 断言不通过 */
Optional<Integer> map3 = o2.map(String::length);
System.out.println("第三个"+map3.get());
}

此时可以得知
1:传入的函数为空,报空指针异常
2:value为空会返回传入的空对象
3:map方法会把原来的Optional转换成另外一个Optional,转换后的泛型取决于函数应用后返回的类型。
3.7 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));
}
}
flatMap与map方法类型,但是有一个很大的区别是flatMap是一个扁平化操作,也就是将可以将多个flatMap连接起来,而map则不行。
这里比较复杂,本人也是查看数据慢慢理解的,避免解释错误,直接上图。

一般来说。我们可以用flatMap用于多层级的属性获取,例如
public static void main(String[] args) {
Apple a1 = new Apple();
a1.setColor("red");
Optional<Apple> optional = Optional.ofNullable(a1);
/*map方法返回的是返回对象上面再封装一层Optional的对象*/
Optional<Optional<String>> map = optional.map(apple->getColor(apple));
/*flatMap方法会将多层Optional转换成一层*/
Optional<String> map2 = optional.flatMap(a->getColor(a));
/*示例 如果要获取某个苹果的颜色对应字符串的长度*/
optional.flatMap(apple->getColor(apple)).map(String::length);
/*第二个方法会编译报错 因为此时第二个map操作的对象是Optional<String>类型 自然没有length方法 */
optional.map(apple->getColor(apple)).map(String::length).map(String::length);
}
public static Optional<String> getColor(Apple apple) {
return Optional.ofNullable(apple.getColor());
}
这个例子中我们就可以先通过flatMap获取颜色的Optional的对象,在获取颜色String的长度。
3.8 orElse
public T orElse(T other) {
return value != null ? value : other;
}
获取value的值,当value是null的时候,返回给定的默认值other

例子中o1因为value有值,所以打印的是value的值hello
o2因为没值,所以打印的是默认值unknown
3.9 orElseGet
此方法和orElse类似,不过使用函数替代了直接的默认值对象

3.10 orElseThrow
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
此方法是,当value为null的时候,抛出传入的指定的异常

4 其他方法
剩下的三个方法是Object通用的equals,hashCode,toString方法,就不再赘述了。