Optional类
1.目录
2.介绍
Optional是一个没有子类的工具类,Optional是一个可以为null的容器对象。它的作用主要就是为了解决避免Null检查,防止NulPointerException
在Javadoc中是这样描述它的:一个可以为null的容器对象。所以java.util.Optional<T>是一个容器类,它可以保存类型为T的值,T可以是实际Java对象,也可以是null
3.原始解决空指针的案例
代码
@Data
public class User {
private String name;
private Address address;
}
@Data public class Address {
private String province;
private String city;
private String area;
}
需求
如果我们需要获取用户所在城市,我们会这么写:
public static String getUserCity(User user) {
return user.getAddress().getCity();
}
String city = getUserCity(user);
问题与原始解决方案
这种写法有可能会报NullPointerException,因为user可能为null,user.getAddress()也有可能为null,所以为了解决这个问题,我们会采用这种写法:
public static String getUserCity(User user) {
if (user != null) {
Address address = user.getAddress();
if (address != null) {
return address.getCity();
}
}
return null;
}
就问这种写法丑不丑?繁琐不繁琐?为了避免这种丑陋的写法,让丑陋的设计变得优雅,Java8提供了Optional
4.API介绍
定义
public final class Optional<T> {
/**
* 如果非空,则为该值;如果为空,则表示没有值存在
*/
private final T value;
}
从这里可以看出,Optional的本质就是内部存储了一个真实的值T,如果T非空,就为该值,如果为空,则表示该值不存在
构造对象
介绍
Optional的构造函数是private权限的,它对外提供了三个方法用于构造Optional对象
Optional.of(T value)
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
所以Optional.of(T value)是创建一个包含非null值的Optional对象。如果传入的值为null,将抛出NullPointerException异常信息
Optional.ofNullable(T value)
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
创建一个包含可能为null值的Optional对象。如果传入的值为null,则会创建一个空的Optional对象
Optional.empty()
private static final Optional<?> EMPTY = new Optional<>();
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY; return t;
}
创建一个空的Optional对象,表示没有值
检查是否有值
介绍
Optional提供了两个方法用来检查是否有值
isPresent()
用于检查Optional对象是否包含一个非null值,源码如下:
public boolean isPresent() {
return value != null;
}
示例如下:
User user = null; Optional<User> optional = Optional.ofNullable(user); System.out.println(optional.isPresent());
// 结果...... false
ifPresent(Consumer<? super T> action)
该方法用来执行一个操作,该操作只有在Optional包含非null值时才会执行。源码如下:
public void ifPresent(Consumer<? super T> consumer) {
if (value != null) consumer.accept(value);
}
示例如下:
User user = new User("xiaoming");
Optional.ofNullable(user).ifPresent(value-> System.out.println("名字是:" + value.getName()));
获取值
介绍
获取值是Optional中的核心API,Optional为该功能提供了四个方法
get()
get()用来获取Optional对象中的值。如果Optional对象的值为空,会抛出NoSuchElementException异常。源码如下:
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
orElse(T other)
orElse()用来获取Optional对象中的值,如果值为空,则返回指定的默认值。源码如下:
public T orElse(T other) {
return value != null ? value : other;
}
示例如下:
User user = null;
user = Optional.ofNullable(user).orElse(new User("xiaohong"));
System.out.println(user);
// 结果...... User(name=xiaohong, address=null)
orElseGet(Supplier<? extends T> other)
orElseGet()用来获取Optional对象中的值,如果值为空,则通过Supplier提供的逻辑来生成默认值。源码如下:
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
示例如下:
User user = null;
user = Optional.ofNullable(user).orElseGet(() -> {
Address address = new Address("湖南省","长沙市","岳麓区");
return new User("xiaohong",address);
});
System.out.println(user);
// 结果...... User(name=xiaohong, address=Address(province=湖南省, city=长沙市, area=岳麓区))
orElseThrow(Supplier<? extends X> exceptionSupplier)
orElseThrow()用来获取Optional对象中的值,如果值为空,则通过Supplier提供的逻辑抛出异常。源码如下:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
示例如下:
User user = null;
user = Optional.ofNullable(user).orElseThrow(() -> new RuntimeException("用户不存在"));
类型转换
介绍
Optional提供map()和flatMap()用来进行类型转换
map(Function<? super T, ? extends U> mapper)
map()允许我们对Optional对象中的值进行转换,并将结果包装在一个新的Optional对象中。该方法接受一个Function函数,该函数将当前Optional对象中的值映射成另一种类型的值,并返回一个新的Optional对应,这个新的Optional对象中的值就是映射后的值。如果当前Optional对象的值为空,则返回一个空的Optional对象,且Function不会执行,源码如下:
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)); }
}
比如我们要获取User对象中的name,如下:
User user = new User("xiaolan");
String name = Optional.ofNullable(user).map(value -> value.getName()).get(); System.out.println(name);
// 结果...... xiaolan
flatMap(Function<? super T, Optional<U>> mapper)
flatMap()与map()相似,不同之处在于flatMap()的映射函数返回的是一个Optional对象而不是直接的值,它是将当前Optional对象映射为另外一个Optional对象
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));
}
}
上面获取 name 的代码如下:
String name = Optional.ofNullable(user).flatMap(value -> Optional.ofNullable(value.getName())).get();
flatMap()内部需要再次封装一个Optional对象,所以flatMap()通常用于在一系列操作中处理嵌套的Optional对象,以避免层层嵌套的情况,使代码更加清晰和简洁
过滤
Optional提供了filter()用于在Optional对象中的值满足特定条件时进行过滤操作,源码如下:
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
filter()接受一个Predicate来对Optional中包含的值进行过滤,如果满足条件,那么还是返回这个Optional;否则返回Optional.empty