在进行Java开发的时候NullPointerException已经算是我们的老朋友了,有些情况没有考虑到就很有可能出现空指针异常,即使考虑到了也要使用类似 if (obj != null){ } 去判断是否为空,这样确实会让代码看上去复杂一些.现在Java8有了Optional之后,空指针的校验就变得非常的方便和简洁,可以理解为将数据作为泛型封装到Optional对象中而形成的空指针预防机制,下面我们就来看看Optional的用法.
1、基本使用
Optional使用起来并不复杂,常用的主要是以下几个方法:
// 创建一个Optional<T>对象,如果传入的value为空则抛出NullPointerException
public static <T> Optional<T> of(T value)
// 创建一个Optional<T>对象,如果传入的value为空则返回一个空的Optional对象(new Optional<>())
public static <T> Optional<T> ofNullable(T value)
// 获取Optional中的值,如果值为空则抛出NoSuchElementException
public T get()
// 判断Optional中的值是否不为空,不为空返回true,反之返回false
public boolean isPresent()
// 判断Optional中的值是否为空,不为空则返回值,为空则返回传入的值
public T orElse(T other)
// 判断Optional中的值是否为空,不为空则返回值,为空则抛出传入的异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
// 传入一个Lambda表达式,返回一个对应的Optional
public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
前面五个方法使用起来都非常的简单,就不一一演示了,主要演示一下最后两个方法
首先创建一个简单的User类
@Data
@AllArgsConstructor
class User {
/**
* 用户id
*/
private Long id;
/**
* 用户名称
*/
private String name;
}
比如现在有这样一个情况,如果User为null或者User下面的name为null都抛出一个NullPointerException,如果是传统的写法就会非常的冗余,阅读性较差
if (user == null) {
throw new NullPointerException("user or name is null");
} else {
if (user.getName() == null || user.getName().isEmpty()) {
throw new NullPointerException("user or name is null");
}
}
但是有了Optional之后一切就变得很方便简洁了,使用一行代码就可以实现,而且可读性也非常高
Optional.ofNullable(user)
.map(temp -> temp.getName())
.orElseThrow(() -> new NullPointerException("user or name is null"));
这段代码用上了ofNullable、map以及orElseThrow三个方法,下面通过源码我们来一一分析一下这三个方法
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public static<T> Optional<T> empty() {
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
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 <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
这里我把需要用到的源码贴了出来,通过源码我们可以将调用的方法链分为三个步骤:
- ofNullable():调用ofNullable方法的时候会对传入的值进行空验证,如果不为空再调用of方法把值设置到成员变量value中去,如果为空则new一个空的Optional(这里的Optional不为null,但是里面的value为null);
- map():调用map方法的时候也会对value进行空验证,如果不为空则进行后面的操作(这里是返回用户的姓名Optional<String>),如果为空则同样new一个空的Optional(这里的Optional不为null,但是里面的value为null);
- orElseThrow():调用orElseThrow方法的时候也会对value进行空验证,如果不为空则返回对应的值,如果为空则抛出一个传入的异常.