如何正确使用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要注意区分使用场景

相关文章
相关标签/搜索