简介
一个可以包含空值或不是空值的容器。如果该值存在则isPresent()
返回true,调用get()
返回这个值。
简而言之就是Optional是一个容器,保存T类型的值或保存null,Optional提供很多方法,这样我们就无需用显示进行空值检查。
jdk1.8后,Optional类的可以很好的解决空指针异常。
源码解析
Optional类有两个属性:
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
EMPTY
是给empty()
静态方法提供的一个空的Optional对象,调用empty()
方法就会返回一个空的Optional对象,若容器内对象非空,则为value
该值,如果为null则value
则不代表任何值。
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
这是empty()
方法,就是返回一个空的Optional<T>
对象。
Optional类有两个构造方法。
private Optional() {
this.value = null;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
第一个是私有的构造方法,它就是提供一个空的实例,也没什么好说的。无非就是在上面EMPTY
属性那里调用了一次,供empty()
方法使用。
第二个构造方法在调用时,对于value
的进行了一次非空检查,如果传入的是null
,则会抛出NullPointerException
,也是私有化的,主要是提供给下面两个方法使用:of(T value)
和ofNullable(T 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);
}
这两个方法就是我们常用用于获取T
类型的Optional<T>
类型对象的方法,of(T value)
方法只是调用了上面提到的Optional(T value)
构造方法,所以它有可能会抛出NullPointerException
异常。
ofNullable(T value)
方法对value
进行了一次空值检查,value == null ? empty() : of(value)
,当传入的value
是null
的时,会调用empty()
方法,将EMPTY
属性返回,也就是一个空的Optional
对象,而当value
非空,会调用of(T value)
方法,返回一个Optional<T>
类型对象。这样就跳过了第二个私有化的构造方法中可能会抛出空指针异常的一步,是引入Optional<T>
的很重要的优点。
继续往下看get()
方法
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
这个方法就是将我们调用of(T value)
或ofNullable(T value)
这连哥哥方法传入的value
返回,当value
为空值时会抛出NoSuchElementException
异常。所以要谨慎使用,建议确认value
不为空时使用。
isPresent()
方法
public boolean isPresent() {
return value != null;
}
这个方法就是对value
进行了一次是否为空的判断。
继续来看下面几个方法:
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
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));
}
}
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));
}
}
这几个方法之所以放在一起是因为他们配合lambda
表达式食用更香。
ifPresent(Consume<T> consumer
方法Consumer
接口,对value
进行空值校验,然后消费这个数据。举个例子:
public static void main(String[] args) {
Optional.ofNullable("abc").ifPresent(System.out::print);
Optional.ofNullable("a,b,c")
.ifPresent(str -> Arrays.stream(str.split(","))
.map(String::toUpperCase)
.forEach(System.out::println));
}
这样直观很多,传进来的"a,b,c"作为value
传进来处理成数组后,转换成大写,然后打印到控制台。
filter(Predicate<? super T> predicate)
方法传入的value经过非空检验后,如果值存在,返回一个Optional
用以描述这个对象,否则的话返回一个空的容器。举一个小例子:
Optional.ofNullable("AbC")
.filter(str -> str.startsWith("A"))
.ifPresent(System.out::println);
可以看出,filter()
方法返回的是一个Optional
对象。
map(Function<? super T, ? extends U> mapper)
做映射后返回一个Optional
对象用以描述返回值,若没有返回值则返回一个空的容器。而flatMap(Function<? super T, Optional<U>> mapper)
需要自己封装返回值成为Optional
去描述返回值。
Optional<char[]> abc = Optional.ofNullable("abc")
.map(s -> s.toCharArray());
Optional<char[]> abc1 = Optional.ofNullable("abc")
.flatMap(s -> Optional.of(s.toCharArray()));
其实区别也就是else
后面的一个调用Optional.ofNullable(T value)
而另一个只是做空值检查而已。前者比后者多一步new Optional<>(value)
操作而已。
下一个方法
public T orElse(T other) {
return value != null ? value : other;
}
看起来很简单是吧,就是这么简单,value
为空,返回我们传入的T类型other
而已,否则返回value
本身。
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
举一个例子吧。
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
Integer integer = integers.stream().reduce(Integer::sum).orElse(get("orElse"));
System.out.println(integer);
Integer orElseGet = integers.stream().reduce(Integer::sum).orElseGet(() -> get("orElseGet"));
System.out.println(orElseGet);
}
private static Integer get(String s) {
System.out.println(s + "执行");
return 1;
}
执行这段代码会得到
orElse执行
15
15
这说明了当Optional
容器中的value
非空时,orElse(T other)
方法需要我们传入的get(String s)
方法的返回值,所以这个方法被执行了,而另一个orElseGet(Supplier<? extends T> other)
并没有这种需求,所以直接返回value
就结束了,并没有执行get(String s)
方法。
我们再看一个例子
public static void main(String[] args) {
ArrayList<Integer> integers1 = new ArrayList<>();
Integer orElse = integers1.stream().reduce(Integer::sum).orElse(get("orElse"));
Integer orElseGet1 = integers1.stream().reduce(Integer::sum).orElseGet(() -> get("orElseGet"));
System.out.println(orElse);
System.out.println(orElseGet1);
}
private static Integer get(String s) {
System.out.println(s + "执行");
return 1;
}
执行结果
orElse执行
orElseGet执行
1
1
说明当value
为空的时候,两个方法都执行了。因为在方法里一个直接返回get(String s)
的值,另一个是通过调用函数式接口返回的值都执行了。
下一个方法
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
这个方法是value
存在返回值,否则抛出由 Supplier
继承的异常。比如这样使用:
Integer integer1 = integers1.stream().reduce(Integer::sum).orElseThrow(NullPointerException::new);
System.out.println(integer1);
结语
其实仔细看里面的方法都不难,但用好Optional能很好的解决空指针异常,所以今天就到这里了。
如果你发现我的文章哪里有错误或者有什么好的想法可以联系我,我们一起学习共同进步,我的邮箱地址是lishuangCHN@gmail.com
let’s do more of those!