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. * If non-null, the value; if null, indicates no value is present
  7. */
  8. 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. public static <T> Optional<T> ofNullable(T value) {
  5. return value == null ? empty() : of(value);
  6. }

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. public T orElseGet(Supplier<? extends T> other) {
  5. return value != null ? value : other.get();
  6. }
  7. public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
  8. if (value != null) {
  9. return value;
  10. } else {
  11. throw exceptionSupplier.get();
  12. }
  13. }

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

4)Optional的中间处理

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

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

现在我有一个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”,了解相关信息可以关注。

如何正确使用Java8的Optional机制相关推荐

  1. Java8使用 Optional 处理 null

    转载自  Java8(5):使用 Optional 处理 null 写过 Java 程序的同学,一般都遇到过 NullPointerException :) -- 为了不抛出这个异常,我们便会写如下的 ...

  2. Java8的Optional是不是鸡肋?

    又是一个阳光明媚的下午,扯淡群里面又在讨论技术,啧啧. 马哥发言道: 原因是他的一位同事请假了,他接手他的代码8天了,要受不了,来看下他同事 Optional 的使用: Optional<Use ...

  3. Java8 HashMap 扩容机制与线程安全分析

    如果大家有仔细阅读过 HashMap 的源码就会发现 HashMap 的哈希表初始化并不是在其构造函数中进行的,而是 resize() 方法. 这篇文章不对 HashMap 中的树进行介绍. 一.Ha ...

  4. 灵活正确的实现.NET插件机制

    .NET提供的反射(Reflection)机制可以很方便的加载插件.本文提供一种方法,可以灵活的正确的载入所需的插件. 在.NET中,一个完整的类型名称的格式如"类型名,程序集名" ...

  5. Java8中Optional的基础使用和实践

    说明 首先我们来看一下Optional的作者 Brian Goetz 对这个 API 的说明: Our intention was to provide a limited mechanism for ...

  6. Java8/9 Optional使用

    Java8 引入的 Optional类.主要用来解决空指针异常(NullPointerException),空指针异常是导致Java应用程序失败的最常见原因. Optional类可以理解为一个容器:它 ...

  7. java8中Optional的使用

    1.Optional对象的创建 创建空的Optional,Optional<T> optT = Optional.empty(),其中T为需要创建的类型,根据实际需要填写 创建非空值的Op ...

  8. java8之Optional案例

    核心代码一 import entity.Student;import java.util.Optional;public class OptonalDemo {public static void m ...

  9. java中npe问题,JAVA8如何用Optional解决NPE问题详解

    引言 NPE(NullPointerException)是调试程序最常见的异常.google一下有很多关于方法到底应该返回null还是new一个空对象的讨论. 在文章的开头,先说下NPE问题,NPE问 ...

最新文章

  1. ICLR 2022|唯快不破!面向极限压缩的全二值化BiBERT
  2. PHP框架中的日志系统
  3. Linux学习---Day02
  4. AI 事件驱动场景 Serverless 实践
  5. 手机 跑linux,你可曾想过在iOS上跑Linux?
  6. 2015.5.28 面试题1:赋值运算符函数
  7. gradle安装及idea导入spring5.0x的源码
  8. 清退117名博士、119名硕士!研究生“严出”成人才培养大趋势
  9. 打造自己的Android源码学习环境之二:在虚拟机中安装Ubuntu(上)
  10. 针式打印机打印发虚_针式打印机打印输出字符模糊不清晰的原因有哪些
  11. 西门子g120变频器接线图_西门子G120变频器通过IOP-2面板初始设置
  12. 转录组-蛋白组-代谢组关联分析
  13. 针对文本文件单行连续多字符内容根据分隔符号转多行方法
  14. Vue 数组/对象赋值,视图不更新问题
  15. 从程序员到项目经理(28):该死的结果导向(只看结果,不问过程到底行不行?)
  16. html内嵌子页面并配合CGI进行页面更新
  17. cairosvg在linux中的安装_Cairo编程
  18. 常见的四种计量标识及其含义(CNAS / ILAC / CMC / CMA)
  19. STM32HAL库电子广告牌显示广告+温湿度+时间设置
  20. 2019年30岁完成从一名程序员转行成一名高中信息技术教师

热门文章

  1. linux检测病毒工具,Linux下查杀病毒工具
  2. resetroot_169route_python2(用于ubuntu12.04和14.04,centos系列)
  3. Linux环境上的图形化界面SVN客户端软件“RabbitVCS”
  4. 基于Ubuntu+Owncloud的私有云网盘
  5. JMeter学习(六)集合点
  6. DirectoryEntry所有字段对应解释
  7. 为什么产品经理这个行业装逼的人这么多?
  8. 资讯类产品的数据驱动增长方法论
  9. PMCAFF携手百度,干货从未如此精彩(现场快讯)
  10. 电商必备:如何选择第三方快递?