Java8带来的函数式编程特性对于习惯命令式编程的程序员来说还是有一定的障碍的,我们只有深入了解这些机制的方方面面才能运用自如。Null的处理在JAVA编程中是出了try catch之外的另一个头疼的问题,需要大量的非空判断模板代码,程序逻辑嵌套层次太深。尤其是对集合的使用,需要层层判空。
首先来看下Optional类的结构图:
属性
/** * Common instance for {@codeempty()}. */privatestaticfinalOptionalEMPTY=newOptional<>();/**
* If non-null, the value; if null, indicates no value is present
*/privatefinalT value;
1) EMPTY持有某个类型的空值结构,调用empty()返回的即是该实例
publicstatic Optional empty() {@SuppressWarnings("unchecked")Optional t = (Optional) EMPTY;returnt; }
2) T vaule是该结构的持有的值
方法
构造函数
privateOptional(){this.value=null; }privateOptional(Tvalue){this.value= Objects.requireNonNull(value); }
Optional(T value)如果vaule为null就会抛出NullPointer异常,所以对于使用的场景这两个构造器都适用.
生成Optional对象
有两个方法 of(T)和ofNullable(T)
publicstaticOptionalof(Tvalue){returnnewOptional<>(value); }publicstaticOptionalofNullable(Tvalue){returnvalue==null? empty() : of(value); }
of是直接调用的构造函数,因此如果T为null则会抛出空指针异常,ofNullable对null进行了处理,会返回EMPTY的实例,因此不会出现异常。
所以只有对于明确不会为null的对象才能直接使用of
获取Optional对象的值
需要摈弃的使用方式
if(value.isPresent){ …. }else{ T t = value.get(); }
这种使用方式无异于传统的if(vaule != null)
正确的使用姿势:
orElse:如果值为空则返回指定的值
orElseGet:如果值为空则调用指定的方法返回
orElseThrow:如果值为空则直接抛出异常
publicTorElse(T other){returnvalue!=null?value: other; }publicTorElseGet(Supplier other){returnvalue!=null?value: other.get(); }publicTorElseThrow(Supplier exceptionSupplier) throws X{if(value!=null) {returnvalue; }else{throwexceptionSupplier.get(); } }
一般我们使用orElse来取值,如果不存在返回默认值.
Optional的中间处理
filter,map,flatMap,这几个操作跟Stream的处理类似,只是要注意flatMap处理必须手动指定返回类型为Optional
,而map会自动将返回值包装成Optional.举个栗子,我们有商品很订单的结构:
packagemodel;importjava.util.List;/** *@authgongxufan *@Date2016/10/23 **/publicclassGoods{privateString goodsName;privatedoubleprice;privateList orderList;publicStringgetGoodsName(){returngoodsName; }publicvoidsetGoodsName(String goodsName){this.goodsName = goodsName; }publicdoublegetPrice(){returnprice; }publicvoidsetPrice(doubleprice){this.price = price; }publicListgetOrderList(){returnorderList; }publicvoidsetOrderList(List orderList){this.orderList = orderList; } }packagemodel;importjava.time.LocalDateTime;/** *@authgongxufan *@Date2016/10/23 **/publicclassOrder{privateLocalDateTime createTime;privateLocalDateTime finishTime;privateString orderName;privateString orderUser;publicLocalDateTimegetCreateTime(){returncreateTime; }publicvoidsetCreateTime(LocalDateTime createTime){this.createTime = createTime; }publicLocalDateTimegetFinishTime(){returnfinishTime; }publicvoidsetFinishTime(LocalDateTime finishTime){this.finishTime = finishTime; }publicStringgetOrderName(){returnorderName; }publicvoidsetOrderName(String orderName){this.orderName = orderName; }publicStringgetOrderUser(){returnorderUser; }publicvoidsetOrderUser(String orderUser){this.orderUser = orderUser; } }
现在我有一个goodsOptional
Optional goodsOptional =Optional.ofNullable(newGoods());
现在我需要获取goodsOptional里边的orderList,应该这样你操作
goodsOptional.flatMap(g->Optional.ofNullable(g.getOrderList())).orElse(Collections.emptyList())
flatMap里头返回的是Optional>,然后我们再使用orElse进行unwraap.因此faltMap可以解引用更深层次的的对象链.
检测Optional并执行动作
publicvoidifPresent(Consumer consumer){if(value!=null) consumer.accept(value); }
这是一个终端操作,不像上边的可以进行链式操作.在Optional实例使用直接调用,如果value存在则会调用指定的消费方法.举个栗子:
Goods goods =newGoods(); Optional goodsOptional = Optional.ofNullable(goods); List orderList =newArrayList<>(); goods.setOrderList(orderList); goodsOptional.flatMap(g ->Optional.ofNullable(g.getOrderList())).ifPresent((v)-> System.out.println(v));
end
至此该类的方法和使用介绍都差不多了,最后总结需要注意的地方:
1) Optional应该只用处理返回值,而不应该作为类的字段或者方法的参数.因为这样会造成额外的复杂度.
2) 使用Option应该避免直接适应构造器和get,而应该使用isElse的系列方法避免频繁的非空判断
3) map和flatMap要注意区分使用场景
网友评论