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()。

posted @ 2019-07-29 18:25  Kobelieve  阅读(1104)  评论(0编辑  收藏  举报