如何正確使用Java8的Optional機制

Java8帶來的函數式編程特性對於習慣命令式編程的程序員來講仍是有必定的障礙的,咱們只有深刻了解這些機制的方方面面才能運用自如。Null的處理在JAVA編程中是出了try catch以外的另外一個頭疼的問題,須要大量的非空判斷模板代碼,程序邏輯嵌套層次太深。尤爲是對集合的使用,須要層層判空。java

首先來看下Optional類的結構圖:
imggit

屬性

/** 
 * Common instance for {@code empty()}. 
 */  
private static final Optional<?> EMPTY = new Optional<>();  
  
/** 
 * If non-null, the value; if null, indicates no value is present 
 */  
private final T value;複製代碼

1) EMPTY持有某個類型的空值結構,調用empty()返回的便是該實例
程序員

public static<T> Optional<T> empty() {  
       @SuppressWarnings("unchecked")  
       Optional<T> t = (Optional<T>) EMPTY;  
       return t;  
   }複製代碼

2) T vaule是該結構的持有的值github

方法

構造函數

private Optional() {  
        this.value = null;  
    }  
private Optional(T value) {  
        this.value = Objects.requireNonNull(value);  
    }複製代碼

Optional(T value)若是vaule爲null就會拋出NullPointer異常,因此對於使用的場景這兩個構造器都適用.編程

生成Optional對象

有兩個方法 of(T)和ofNullable(T)
bash

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);  
    }複製代碼

of是直接調用的構造函數,所以若是T爲null則會拋出空指針異常,ofNullable對null進行了處理,會返回EMPTY的實例,所以不會出現異常。函數式編程

因此只有對於明確不會爲null的對象才能直接使用of函數

獲取Optional對象的值

須要擯棄的使用方式ui

if(value.isPresent){
….
}else{
T t = value.get();
}this

這種使用方式無異於傳統的if(vaule != null)
正確的使用姿式:

orElse:若是值爲空則返回指定的值
orElseGet:若是值爲空則調用指定的方法返回
orElseThrow:若是值爲空則直接拋出異常

public T orElse(T other) {  
    return value != null ? value : other;  
}  
  
public T orElseGet(Supplier<? extends T> other) {  
    return value != null ? value : other.get();  
}  
  
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {  
    if (value != null) {  
        return value;  
    } else {  
        throw exceptionSupplier.get();  
    }  
}複製代碼

通常咱們使用orElse來取值,若是不存在返回默認值.

Optional的中間處理

filter,map,flatMap,這幾個操做跟Stream的處理相似,只是要注意flatMap處理必須手動指定返回類型爲Optional,而map會自動將返回值包裝成Optional.舉個栗子,咱們有商品很訂單的結構:

package model;  
  
import java.util.List;  
  
/** 
 * @auth gongxufan 
 * @Date 2016/10/23
 **/  
public class Goods {  
    private String goodsName;  
    private double price;  
    private List<Order> orderList;  
  
    public String getGoodsName() {  
        return goodsName;  
    }  
  
    public void setGoodsName(String goodsName) {  
        this.goodsName = goodsName;  
    }  
  
    public double getPrice() {  
        return price;  
    }  
  
    public void setPrice(double price) {  
        this.price = price;  
    }  
  
    public List<Order> getOrderList() {  
        return orderList;  
    }  
  
    public void setOrderList(List<Order> orderList) {  
        this.orderList = orderList;  
    }  
}  

package model;  
  
import java.time.LocalDateTime;  
  
/** 
 * @auth gongxufan 
 * @Date 2016/10/23
 **/  
public class Order {  
    private LocalDateTime createTime;  
    private LocalDateTime finishTime;  
    private String orderName;  
    private String orderUser;  
  
    public LocalDateTime getCreateTime() {  
        return createTime;  
    }  
  
    public void setCreateTime(LocalDateTime createTime) {  
        this.createTime = createTime;  
    }  
  
    public LocalDateTime getFinishTime() {  
        return finishTime;  
    }  
  
    public void setFinishTime(LocalDateTime finishTime) {  
        this.finishTime = finishTime;  
    }  
  
    public String getOrderName() {  
        return orderName;  
    }  
  
    public void setOrderName(String orderName) {  
        this.orderName = orderName;  
    }  
  
    public String getOrderUser() {  
        return orderUser;  
    }  
  
    public void setOrderUser(String orderUser) {  
        this.orderUser = orderUser;  
    }  
}複製代碼

如今我有一個goodsOptional

Optional<Goods> goodsOptional = Optional.ofNullable(new Goods());複製代碼

如今我須要獲取goodsOptional裏邊的orderList,應該這樣你操做

goodsOptional.flatMap(g ->Optional.ofNullable(g.getOrderList())).orElse(Collections.emptyList())複製代碼

flatMap裏頭返回的是Optional>,而後咱們再使用orElse進行unwraap.所以faltMap能夠解引用更深層次的的對象鏈.

檢測Optional並執行動做

public void ifPresent(Consumer<? super T> consumer) {  
        if (value != null)  
            consumer.accept(value);  
    }複製代碼

這是一個終端操做,不像上邊的能夠進行鏈式操做.在Optional實例使用直接調用,若是value存在則會調用指定的消費方法.舉個栗子:

Goods goods = new Goods();  
Optional<Goods> goodsOptional = Optional.ofNullable(goods);  
List<Order> orderList = new ArrayList<>();  
goods.setOrderList(orderList);  
goodsOptional.flatMap(g ->Optional.ofNullable(g.getOrderList())).ifPresent((v)-> System.out.println(v));複製代碼

end

至此該類的方法和使用介紹都差很少了,最後總結須要注意的地方:1) Optional應該只用處理返回值,而不該該做爲類的字段或者方法的參數.由於這樣會形成額外的複雜度.2) 使用Option應該避免直接使用構造器和get,而應該使用orElse的系列方法避免頻繁的非空判斷3) map和flatMap要注意區分使用場景

相關文章
相關標籤/搜索