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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM