Java8Optional机制的正确使用方式Java8带来的函数式编程特性对于习惯命令式编程的程序员来说还是有一定的障碍的,我们只有深入了 解这些机制的方方面面才能运用自如。Null的处理在JAVA编程中是出了trycatch之外的另一个头疼的问题,需要大量的非空判断 模板代码,程序逻辑嵌套层次太深。尤其是对集合的使用,需要层层判空。属性?123456789/?Commoninstan cefor{@codeempty()}.?/?privatestaticfinalOptionalEMPTY= newOptional<>();???/?Ifnon-null,thevalue;ifnull,ind icatesnovalueispresent?/?privatefinalTvalue;1)EMPTY持有某个 类型的空值结构,调用empty()返回的即是该实例?12345publicstaticOptionalempty (){??@SuppressWarnings("unchecked")??Optionalt=(Optional )EMPTY;??returnt;??}2)Tvaule是该结构的持有的值方法构 造函数?123456privateOptional(){??this.value=null;??}?private Optional(Tvalue){??this.value=Objects.requireNonNull(value); ??}Optional(Tvalue)如果vaule为null就会抛出NullPointer异常,所以对于使用的场景这两个构造 器都适用.生成Optional对象有两个方法of(T)和ofNullable(T)?1234567publicstatic< t>Optionalof(Tvalue){??returnnewOptional<>(value);??}? ???publicstaticOptionalofNullable(Tvalue){??return value==nullempty():of(value);??}of是直接调用的构造函 数,因此如果T为null则会抛出空指针异常,ofNullable对null进行了处理,会返回EMPTY的实例,因此不会出现异常。所 以只有对于明确不会为null的对象才能直接使用of获取Optional对象的值需要摈弃的使用方式?1if(value.isPres ent){….}else{Tt=value.get();}这种使用方式无异于传统的if(vaule!=null) 正确的使用姿势:orElse:如果值为空则返回指定的值orElseGet:如果值为空则调用指定的方法返回orElseThrow:如 果值为空则直接抛出异常?123456789101112131415publicTorElse(Tother){??ret urnvalue!=nullvalue:other;?}???publicTorElseGet(Supplie rother){??returnvalue!=nullvalue:other. get();?}???publicTorElseThrow(Sup plierexceptionSupplier)throwsX{??if(value !=null){??returnvalue;??}else{??throwexceptionSupplier.g et();??}?}一般我们使用orElse来取值,如果不存在返回默认值.Optional的中间处理filter,ma p,flatMap,这几个操作跟Stream的处理类似,只是要注意flatMap处理必须手动指定返回类型为Optional,而ma p会自动将返回值包装成Optional.举个栗子,我们有商品很订单的结构:?123456789101112131415161718 19202122232425262728293031323334353637383940414243444546474849505 15253545556575859606162636465666768697071727374757677787980818283 84packagemodel;???importjava.util.List;???/?@authgongxu fan?@Date2016/10/23?/?publicclassGoods{??privateString goodsName;??privatedoubleprice;??privateListorderLi st;????publicStringgetGoodsName(www.77884.net){??returngood sName;??}????publicvoidsetGoodsName(StringgoodsName){??thi s.goodsName=goodsName;??}????publicdoublegetPrice(){??ret urnprice;??}????publicvoidsetPrice(doubleprice){??this.pr ice=price;??}????publicListgetOrderList(www.44771.ne t){??returnorderList;??}????publicvoidsetOrderList(Listder>orderList){??this.orderList=orderList;??}?}??package model;???importjava.time.LocalDateTime;???/?@authgongxuf an?@Date2016/10/23?/?publicclassOrder{??privateLocalDa teTimecreateTime;??privateLocalDateTimefinishTime;??private StringorderName;??privateStringorderUser;????publicLocalDat eTimegetCreateTime(){??returncreateTime;??}????publicvoid setCreateTime(LocalDateTimecreateTime){??this.createTime=cre ateTime;??}????publicLocalDateTimegetFinishTime(){??return finishTime;??}????publicvoidsetFinishTime(LocalDateTimefinis hTime){??this.finishTime=finishTime;??}????publicStringge tOrderName(){??returnorderName;??}????publicvoidsetOrderNa me(StringorderName){??this.orderName=orderName;??}????publ icStringgetOrderUser(www.ff787.com){??returnorderUser;??}? ???publicvoidsetOrderUser(StringorderUser){??this.orderUser =orderUser;??}?}现在我有一个goodsOptional?1O ptionalgoodsOptional=Optional.ofNullable(newGoods());< /goods>现在我需要获取goodsOptional里边的orderList,应该这样你操作?1goodsOptional.fl atMap(g->Optional.ofNullable(g.getOrderList())).orElse(Collectio ns.emptyList())flatMap里头返回的是Optional>,然后我们再使用orElse进行unwraap.因此fa ltMap可以解引用更深层次的的对象链.检测Optional并执行动作?1234publicvoidifPresent(Con sumerconsumer){??if(value!=null)??consumer. accept(value);??}这是一个终端操作,不像上边的可以进行链式操作.在Optional实例使用直接调用,如果valu e存在则会调用指定的消费方法.举个栗子:?12345Goodsgoods=newGoods();?Optionalods>goodsOptional=Optional.ofNullable(goods);?Listord erList=newArrayList<>();?goods.setOrderList(orderList);?good sOptional.flatMap(g->Optional.ofNullable(g.getOrderList())).ifPresent((v)->System.out.println(v));end至此该类的方法和使用介绍都差不多了,最后总结需要注意的地方:1)Optional应该只用处理返回值,而不应该作为类的字段或者方法的参数.因为这样会造成额外的复杂度.2)使用Option应该避免直接适应构造器和get,而应该使用isElse的系列方法避免频繁的非空判断3)map和flatMap要注意区分使用场景 |
|