jdk1.8新特性之Optional
一、传统写法
@Data
public class SkuVO {
private Long skuId;
private Price price;
}
@Data
public class Price {
private BigDecimal mallPrice;
private BigDecimal sellPrice;
}
有一个SKU对象,里面包含一个skuId和一个price对象,price对象里面有市场价和成本价。假如现在有个需求,获取sku里面的mallPrice,并且返回。
毫无疑问,NPE相信每个程序员都不可能没遇到过。jdk1.8以前一般是这么写:
private static BigDecimal fetchMallprice(SkuVO skuVO) throws Exception {
if (skuVO != null) {
Price price = skuVO.getPrice();
if (price != null) {
BigDecimal mallPrice = price.getMallPrice();
if (mallPrice != null) {
if (mallPrice.compareTo(new BigDecimal("10")) == 1) {
return mallPrice;
}
}
}
}
throw new Exception("skuVO不符合要求,请检查");
}
其实在真实项目中,这种写法实在是太普遍了,各种非空判断才敢往下执行,否则就会抛出NPE。但是这种写法if嵌套得太多了,可读性很差。
所以我们也可以像这样,提前判断是否为空,为空则抛异常:
private static BigDecimal fetchMallprice(SkuVO skuVO) throws Exception {
if (skuVO == null) {
throw new Exception("skuVO不符合要求,请检查");
}
Price price = skuVO.getPrice();
if (price == null) {
throw new Exception("skuVO不符合要求,请检查");
}
BigDecimal mallPrice = price.getMallPrice();
if (mallPrice != null) {
if (mallPrice.compareTo(new BigDecimal("10")) == 1) {
return mallPrice;
}
}
throw new Exception("skuVO不符合要求,请检查");
}
虽然嵌套减少了,但是还是比较臃肿的。JDK1.8出来后,我们就可以优雅地写这种功能了。
二、JDK1.8写法
private static BigDecimal fetchMallprice(SkuVO skuVO) throws Exception {
return Optional.ofNullable(skuVO)
.map(s -> s.getPrice())
.map(p -> p.getMallPrice())
.filter(m -> m.compareTo(new BigDecimal("10")) == 1)
.orElseThrow(() -> new Exception("skuVO不合法"));
}
Optional是jdk1.8出的新特性,其实思想挺简单的,就是把实体包装了一层,包装的时候,如果是实体为空,则返回一个空的Optional,否则返回Optional。
Optional.ofNullable(skuVO)首先构造一个Optional,map(Function<? super T, ? extends U> mapper)接收一个Funtion,filter过滤map返回的值,最后通过orElseThrow抛出异常。
三、源码分析
3.1 构造方法
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
private Optional() {
this.value = null;
}
Optional的构造方法都是private,所以其提供了三个静态public方法来构造Optional:
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
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);
}
EMPTY是当Optional为空的时候返回的。
T是实际值。
empty()方法返回一个空实例EMPTY,即Optional里面不包含值,那么我们使得 Optional 只存在 包含值 和 不包含值 两种状态。
of(T value)方法将新建一个非空的Optional,如果value为空,那么会抛出NPE。
ofNullable(T value)方法里的value可以为空,如果为空,则调用empty()方法空的Optional,否则调用of(T value)方法一个非空的Optional。
3.2 ifPresent
public void ifPresent(Consumer<? super T> consumer) {
if (value != null) {
consumer.accept(value);
}
}
如果当前Optional不为空,则调用consumer.accept(value)方法,而Consumer又是函数式接口,故利用lambda表达式可以这样写:
Optional<SkuVo> sku = Optional.ofNullable(getSku());
sku.ifPresent(s -> System.out.println(s.getSkuId()));
3.3 orElse
public T orElse(T other) {
return value != null ? value : other;
}
如果Optional不为空,则返回,否则执行orElse传入的参数。
3.4 orElseGet
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
如果Optional不为空,则返回,否则返回Supplier实现类的值,Supplier也是函数式接口,里面只有get()方法。
3.5 orElseThrow
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
同orElseGet,只是但当Optional为空的时候,会抛出异常,抛出的异常由传入的异常exceptionSupplier提供。
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));
}
}
当Optional为空的时候,返回empty(),否则返回一个新的Optional,该Optional包装的是mapper以value作为输入的输出值。
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方法的区别是,map方法参数中的mapper输出的是值,map方法会使用Optional.ofNullable将其包装成Optional,而flatMap要求参数中的mapper输出的就是Optional。
3.8 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来对Optional包含的值进行过滤,如果包含的值满足条件,那么还是返回这个Optional,否则返回empty()。