The functional programming features introduced by Java8 are a bit of a hurdle for programmers used to imperative programming, and we need to understand all aspects of these mechanisms to be comfortable with them. Null handling is another headache in JAVA programming besides try Catch. It requires a lot of non-null judgment template code, and the program logic is too deeply nested. In particular, the use of sets requires layer upon layer nulling.

The Optional class looks like this:

attribute

/** 
 * 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;Copy the code

1) EMPTY holds an EMPTY value structure of a type, which is returned by calling EMPTY ()

public static<T> Optional<T> empty() {  
       @SuppressWarnings("unchecked")  
       Optional<T> t = (Optional<T>) EMPTY;  
       return t;  
   }Copy the code

2) T vaule is the value held by the structure

methods

The constructor

private Optional() {  
        this.value = null;  
    }  
private Optional(T value) {  
        this.value = Objects.requireNonNull(value);  
    }Copy the code

Optional(T Value) Raises a NullPointer exception if vaule is null, so both constructors work for the scenario used.

Generating Optional objects

There are two methods: of(T) and ofNullable(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);  
    }Copy the code

OfNullable handles null and returns an instance of EMPTY, so no exception is raised.

So you can only use of directly for objects that are explicitly not null

Gets the value of the Optional object

Use methods that need to be discarded

If (value. IsPresent) {… . }else{ T t = value.get(); }

This is no different from the traditional if(Vaule! = null) Correct use of posture:

OrElse: returns the specified value if the value is null. OrElseGet: calls the specified method if the value is null. Returns orElseThrow: throws an exception if the value is null

public T orElse(T other) {  
    returnvalue ! = null ? value : other; } public T orElseGet(Supplier<? extends T> other) {returnvalue ! = 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(); }}Copy the code

Generally we use orElse for the value, if there is no default value returned.

Optional intermediate processing

The filter,map, and flatMap operations are similar to the Stream handlers, except that the flatMap handler must manually specify the return type as Optional, and the map automatically wraps the return value as Optional. For example, we have an order structure for goods:

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; }}Copy the code

Now I have a goodsOptional

Optional<Goods> goodsOptional = Optional.ofNullable(new Goods());Copy the code

Now I need to get the orderList from goodsOptional, so you should do that

goodsOptional.flatMap(g ->Optional.ofNullable(g.getOrderList())).orElse(Collections.emptyList())Copy the code

FlatMap returns Optional>, and then we unwraAP using orElse. So faltMap can dereference deeper chains of objects.

Check Optional and perform the action

public void ifPresent(Consumer<? super T> consumer) {  
        if(value ! = null) consumer.accept(value); }Copy the code

This is a terminal operation, not a chain operation. A direct call is used in the Optional instance, which calls the specified consumption method if value exists. Here’s an example:

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));Copy the code

end

1) Optional should only be used as a return value, not as an argument to a class field or method. 2) The use of options should avoid the direct use of constructors and get, and instead use orElse’s series of methods to avoid frequent non-null judgments. 3) Map and flatMap should be used in different scenarios