如何正确使用Java8的Optional机制

Java8带来的函数式编程特性对于习惯命令式编程的程序员来说还是有一定的障碍的,我们只有深入了解这些机制的方方面面才能运用自如。Null的处理在JAVA编程中是出了try catch之外的另一个头疼的问题,需要大量的非空判断模板代码,程序逻辑嵌套层次太深。尤其是对集合的使用,需要层层判空。

首先来看下Optional类的结构图:

1,Optional拥有两个字段


  1. /** 
  2.      * Common instance for {@code empty()}. 
  3.      */ 
  4.     private static final Optional<?> EMPTY = new Optional<>(); 
  5.  
  6.     /** 
  7.      * If non-null, the value; if null, indicates no value is present 
  8.      */ 
  9.     private final T value;  

1)EMPTY持有某个类型的空值结构,调用empty()返回的即是该实例


  1. public static<T> Optional<T> empty() { 
  2.         @SuppressWarnings("unchecked") 
  3.         Optional<T> t = (Optional<T>) EMPTY; 
  4.         return t; 
  5.     }  

2)T vaule是该结构的持有的值

2,Optional的方法

1)构造函数


  1. private Optional() { 
  2.         this.value = null; 
  3.     } 
  4. private Optional(T value) { 
  5.         this.value = Objects.requireNonNull(value); 
  6.     }  

Optional(T value)如果vaule为null就会抛出NullPointer异常,所以对于使用的场景这两个构造器都适用.

2)生成Optional对象

有两个方法 of(T)和ofNullable(T)


  1. public static <T> Optional<T> of(T value) { 
  2.         return new Optional<>(value); 
  3.     } 
  4.  
  5.  public static <T> Optional<T> ofNullable(T value) { 
  6.         return value == null ? empty() : of(value); 
  7.     }  

of是直接调用的构造函数,因此如果T为null则会抛出空指针异常

ofNullable对null进行了处理,会返回EMPTY的实例,因此不会出现异常

所以只有对于明确不会为null的对象才能直接使用of

3)获取Optional对象的值

需要摈弃的使用方式

if(value.isPresent){

....

}else{

T t = value.get();

}

这种使用方式无异于传统的if(vaule != null)

正确的使用姿势:

orElse:如果值为空则返回指定的值

orElseGet:如果值为空则调用指定的方法返回

orElseThrow:如果值为空则直接抛出异常


  1. public T orElse(T other) { 
  2.         return value != null ? value : other; 
  3.     } 
  4.  
  5.     public T orElseGet(Supplier<? extends T> other) { 
  6.         return value != null ? value : other.get(); 
  7.     } 
  8.  
  9.     public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 
  10.         if (value != null) { 
  11.             return value; 
  12.         } else { 
  13.             throw exceptionSupplier.get(); 
  14.         } 
  15.     }  

一般我们使用orElse来取值,如果不存在返回默认值.

4)Optional的中间处理

filter,map,flatMap,这几个操作跟Stream的处理类似,只是要注意flatMap处理必须手动指定返回类型为Optional<U>,而map会自动将返回值包装成Optional.举个栗子,我们有商品很订单的结构:


  1. package model; 
  2.  
  3. import java.util.List; 
  4.  
  5. /** 
  6.  * @auth gongxufan 
  7.  * @Date 2017/10/23 
  8.  **/ 
  9. public class Goods { 
  10.     private String goodsName; 
  11.     private double price; 
  12.     private List<Order> orderList; 
  13.  
  14.     public String getGoodsName() { 
  15.         return goodsName; 
  16.     } 
  17.  
  18.     public void setGoodsName(String goodsName) { 
  19.         this.goodsName = goodsName; 
  20.     } 
  21.  
  22.     public double getPrice() { 
  23.         return price; 
  24.     } 
  25.  
  26.     public void setPrice(double price) { 
  27.         this.price = price; 
  28.     } 
  29.  
  30.     public List<Order> getOrderList() { 
  31.         return orderList; 
  32.     } 
  33.  
  34.     public void setOrderList(List<Order> orderList) { 
  35.         this.orderList = orderList; 
  36.     } 
  37. }  

  1. package model; 
  2.  
  3. import java.time.LocalDateTime; 
  4.  
  5. /** 
  6.  * @auth gongxufan 
  7.  * @Date 2017/10/23 
  8.  **/ 
  9. public class Order { 
  10.     private LocalDateTime createTime; 
  11.     private LocalDateTime finishTime; 
  12.     private String orderName; 
  13.     private String orderUser; 
  14.  
  15.     public LocalDateTime getCreateTime() { 
  16.         return createTime; 
  17.     } 
  18.  
  19.     public void setCreateTime(LocalDateTime createTime) { 
  20.         this.createTime = createTime; 
  21.     } 
  22.  
  23.     public LocalDateTime getFinishTime() { 
  24.         return finishTime; 
  25.     } 
  26.  
  27.     public void setFinishTime(LocalDateTime finishTime) { 
  28.         this.finishTime = finishTime; 
  29.     } 
  30.  
  31.     public String getOrderName() { 
  32.         return orderName; 
  33.     } 
  34.  
  35.     public void setOrderName(String orderName) { 
  36.         this.orderName = orderName; 
  37.     } 
  38.  
  39.     public String getOrderUser() { 
  40.         return orderUser; 
  41.     } 
  42.  
  43.     public void setOrderUser(String orderUser) { 
  44.         this.orderUser = orderUser; 
  45.     } 
  46. }  

现在我有一个goodsOptional


  1. Optional<Goods> goodsOptional = Optional.ofNullable(new Goods()); 

现在我需要获取goodsOptional里边的orderList,应该这样你操作


  1. goodsOptional.flatMap(g ->Optional.ofNullable(g.getOrderList())).orElse(Collections.emptyList()) 

flatMap里头返回的是Optional<List<Order>>,然后我们再使用orElse进行unwraap.因此faltMap可以解引用更深层次的的对象链.

5)检测Optional并执行动作


  1. public void ifPresent(Consumer<? super T> consumer) { 
  2.         if (value != null) 
  3.             consumer.accept(value); 
  4.     }  

这是一个终端操作,不像上边的可以进行链式操作.在Optional实例使用直接调用,如果value存在则会调用指定的消费方法.举个栗子:


  1. Goods goods = new Goods(); 
  2.  Optional<Goods> goodsOptional = Optional.ofNullable(goods); 
  3.  List<Order> orderList = new ArrayList<>(); 
  4.  goods.setOrderList(orderList); 
  5.  goodsOptional.flatMap(g ->Optional.ofNullable(g.getOrderList())).ifPresent((v)-> System.out.println(v));  

至此该类的方法和使用介绍都差不多了,最后总结需要注意的地方:

1)Optional应该只用处理返回值,而不应该作为类的字段或者方法的参数.因为这样会造成额外的复杂度.

2)使用Option应该避免直接适应构造器和get,而应该使用isElse的系列方法避免频繁的非空判断

3)map和flatMap要注意区分使用场景  

原文发布时间为:2017-10-31

本文作者:吹着空调盖被子

本文来自合作伙伴“51CTO”,了解相关信息可以关注。

时间: 2024-08-03 10:29:25

如何正确使用Java8的Optional机制的相关文章

正确理解cookie和session机制原理

 php中cookie和session是我们常用的两个变量了,一个是用户客户端的,一个用在服务器的但他们的区别与工作原理怎么样,下面我们一起来看看cookie和session机制原理吧.   cookie和session机制之间的区别和联系 具体来说cookie机制采用的是在客户端保持状态的方案.它是在用户端的会话状态的存贮机制,他需要用户打开客户端的cookie支持.cookie的作用就是为了解决HTTP协议无状态的缺陷所作的努力. 而session机制采用的是一种在客户端与服务器之间保持状态

深入对比数据科学工具箱:Python和R的异常处理机制

概述 异常处理,是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况(即超出程序正常执行流程的某些特殊条件).Python和R作为一门编程语言自然也是有各自的异常处理机制的,异常处理机制在代码编写中扮演着非常关键的角色,却又是许多人容易混淆的地方.对于异常机制的合理运用是直接关系到码农饭碗的事情!所以,本文将具体介绍一下Python和R的异常处理机制,阐明二者在异常处理机制上的异同. 异常安全 在了解Python和R的异常机制之前,我们有必要了解一下异常安全的概念. 根据W

三中全会决定:健全网络突发事件处置机制

摘要: 中共十八届三中全会审议通过的<中共中央关于全面深化改革若干重大问题的决定>今日全文播发.<决定>指出,健全基础管理.内容管理.行业管理以及网络违法犯罪防范和打击等 中共十八届三中全会审议通过的<中共中央关于全面深化改革若干重大问题的决定>今日全文播发.<决定>指出,健全基础管理.内容管理.行业管理以及网络违法犯罪防范和打击等工作联动机制,健全网络突发事件处置机制,形成正面引导和依法管理相结合的网络舆论工作格局. <决定>提出,完善文化管理

【转载】关于移动端的钓鱼式攻击

转载自coolshell: http://coolshell.cn/articles/17066.html  今天,在微博上看了一篇<微信和淘宝到底是谁封谁>的文章,我觉得文章中逻辑错乱,所以,我发了一篇关于这篇文章逻辑问题的长微博.后面,我被原博主冷嘲热讽了一番,说是什么鸡汤啊,什么我与某某之流的人在一起混淆视听啊,等等.并且也有一些网友找我讨论一下相关的钓鱼式攻击的技术问题.所以,我想写下这篇纯技术文章,因为我对那些商业利益上的东西不关心,所以,只谈技术,这样最简单. 首先说明一下,我个人

社保行业信息泄露 安华金和提应对方案

本文讲的是社保行业信息泄露 安华金和提应对方案,针对今日全网大规模报道的全国30省市社保用户信息泄露事件,安华金和对乌云历史报道的社保行业相关漏洞进行集中分析,得出的结论为:大量的信息泄露主要由软件中存在的SQL注入漏洞引起,而且由外部黑客入侵引起. 实际上根据安华金和对社保行业的掌握情况,不仅仅是外部黑客,同时社保内部的运维人员.第三方的开发人员.甚至社保系统的业务人员都可以通过直连到数据库,查看或修改相关信息,从而引起社保数据的批量泄露或篡改. 这些问题的解决需要一个系统化的方法,包括管理制

自动化测试技巧之结果验证

自动到了京城,已经两月没有好好整理下自己的思路了,也没有好好的写一些东西了.现在,真应该回归了.因为有的东西,不吐不快. --------------------------------------------------------------- 在这里整理下关于自动化测试技巧中的结果验证的一些东西吧,这块也是我当年一个一个坑走出来的,虽然现在还有很多坑在等着我. 在我们编写测试脚本的过程中,很多时候总会不知道该怎么去判断我们的结果是否正确.因为有一些操作涉及图形.一些操作涉及页面窗口变化.一

基本线程同步(二)同步方法

同步方法 在这个指南中,我们将学习在Java中如何使用一个最基本的同步方法,即使用 synchronized关键字来控制并发访问方法.只有一个执行线程将会访问一个对象中被synchronized关键字声明的方法.如果另一个线程试图访问同一个对象中任何被synchronized关键字声明的方法,它将被暂停,直到第一个线程结束方法的执行. 换句话说,每个方法声明为synchronized关键字是一个临界区,Java只允许一个对象执行其中的一个临界区. 静态方法有不同的行为.只有一个执行线程访问被sy

英伟达:超高的性能表现……足以支持AI应用

英伟达公司已经为AI应用设计出两款全新Tesla处理器,分别为P4与P40.   这款16纳米FinFET GPU采用英伟达Pascal架构,且延续今年6月发布的P100命名方式.其中P4为单高.单长PCIe卡,用于向外扩展服务器:而更为强大的P40则着眼于向上扩展设备. 这一新组合主要用于推理工作,即在硬件当中内置一套经过训练的AI模型.部分对应软件以及类似摄像头视频或者麦克风音频的输入数据,并由其据此提供决策.语音到文本转换以及对象分类等功能. 如今我们的深度学习模型已经发展到新的阶段--即

iOS夯实:ARC时代的内存管理

iOS夯实:ARC时代的内存管理 什么是ARC Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. Rather than having to think about retain and release operations [^1] [^1]: Transitioning to ARC Release