背景
在平时开发的过程中,在使用一个对象的时候,会先进行空的判断,在非空的情况下,才能获取这个对象的属性值,否则会报NPE(NullPointerException),所以为了解决NullPointerException问题,减少代码中的判空,Java8引入了一个新的Optional类。
介绍
-
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
-
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
-
Optional 类的引入很好的解决空指针异常。
长什么样呢?如下
public String result(User user) {
String result = Optional.ofNullable(user)
.map(User::getSchool)
.map(School::getClass)
.map(Class::getName)
.orElse("null");
return result;
}
复制代码
API
1. 创建optional实例
Optional、empty、of、ofNullabe
- Optional:构造函数,可以看到是private,也就是不能从外部调用。
private static final Optional<?> EMPTY = new Optional<>();
复制代码
- empty:返回一个空的optional对象
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
复制代码
- of:为非null的值创建一个Optional。
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
复制代码
- ofNullable:如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。
源码:
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
使用
Optional<User> opt = Optional.ofNullable(user);
复制代码
通过源码可以看出of和ofNullabe的区别:
当value为空时,of会报空指针异常,而ofNullabe会返回一个空optional
2. 获取optional对象的值
get:如果Optional有值则将其返回,否则抛出NoSuchElementException,所以在用之前需要判空
源码:
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
使用:
User user = Optional.get();
复制代码
注:避免使用Optional.get()。如果你不能证明是否有值,那么永远不要调用get()
3. 判断是否存在
isPresent()和ifPresent(Consumer<? super T> consumer)
- isPresent():如果值存在则方法会返回true,否则返回 false
源码:
public boolean isPresent() {
return value != null;
}
使用:
if (opt.isPresent()) {
//do something
}
复制代码
- ifPresent(Consumer<? super T> consumer):如果值存在则使用该值调用 consumer , 否则不做任何事情。
源码
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
使用
optional.ifPresent(s -> {
//do something
});
复制代码
4. 返回默认值
orElse(T other)、orElseGet(Supplier<? extends T> other)和orElseThrow(Supplier<? extends X> exceptionSupplier)
- orElse:如果有值则将其返回,否则返回指定的其它值
源码
public T orElse(T other) {
return value != null ? value : other;
}
使用
User user=Optional.offNullable(user).orElse(createUser());
复制代码
- orElseGet:如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果
源码
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
使用
User user=Optional.offNullable(user).orElseGet(createUser());
复制代码
咋一看,好像没什么区别,这两者真正的区别在于,orElse不管optional对象是否空,都会触发createUser()方法;而orElseGet只有在空的情况下,才会触发createUser()。
- orElseThrow:如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
源码
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
使用
Optional.ofNullable(user).orElseThrow(()->new Exception("用户为空"));
复制代码
5. 转换值
map(Function<? super T, ? extends U> mapper)和flatMap(Function<? super T, Optional<U>> mapper)
- map:如果有值,则对其执行调用映射函数得到返回值,否则返回空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.ofNullable(user).map(u-> u.getName());
复制代码
- flatMap:如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
Optional.ofNullable(user).map(u-> u.getName());源码
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));
}
}
使用
Optional.ofNullable((user).map(u-> Optional.ofNullable(u.getName());
复制代码
区别:flatMap和map的区别在于接收的参数不同。
6. 过滤值
filter(Predicate<? super predicate)
如果值存在,并且这个值匹配给定的 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();
}
使用:name不为空则返回,否则返回空optional
Optional<User> opt = Optional.ofNullable(user).filter(u -> u.getName() != null);
复制代码
总结
Optional是为了解决空指针异常,但并不能一上来就用,一些简单的代码即可达到目的
使用Optional后,虽然代码优雅了,但是逻辑性没那么明显,可读性也变差了。
所以不可滥用,酌情使用。比如:当你在返回值不确定的时候,可以使用optional作为返回类型。
关注公众号:臻大虾,分享更多java干货
近期评论