1.Optional介绍

Optional<T>是在java.util包下的一个用于代替null的一个工具类

2. Optional的构造方法

JDK 提供三个静态方法来构造一个Optional:

2.1 Optional.of(T value),该方法通过一个非 null 的 value 来构造一个 Optional,返回的 Optional 包含了 value 这个值。对于该方法,传入的参数一定不能为 null,否则便会抛出 NullPointerException。

2.2 Optional.ofNullable(T value),该方法和 of 方法的区别在于,传入的参数可以为 null , 但是前面 javadoc 不是说 Optional 只能包含非 null 值吗?原来该方法会判断传入的参数是否为 null,如果为 null 的话,返回的就是 Optional.empty()。

2.3 Optional.empty(),该方法用来构造一个空的 Optional,即该 Optional 中不包含值,其实底层实现还是 如果 Optional 中的 value 为 null 则该 Optional 为不包含值的状态,然后在 API 层面将 Optional 表现的不能包含 null 值,使得 Optional 只存在 包含值 和 不包含值 两种状态。

3. Optional的相关方法介绍

3.1 ifPresent

如果 Optional 中有值,则对该值调用 consumer.accept,否则什么也不做。
所以对于上面的例子,我们可以修改为:

Optional<User> user = Optional.ofNullable(getUserById(id));
user.ifPresent(u -> System.out.println("Username is: " + u.getUsername()));

3.1 orElse

如果 Optional 中有值则将其返回,否则返回 orElse 方法传入的参数。

User user = Optional.ofNullable(getUserById(id)).orElse(new User(0, "Unknown"));System.out.println("Username is: " + user.getUsername());

3.3 orElseGet

orElseGet 与 orElse 方法的区别在于,orElseGet 方法传入的参数为一个 Supplier 接口的实现 —— 当 Optional 中有值的时候,返回值;当 Optional 中没有值的时候,返回从该 Supplier 获得的值。

User user = Optional.ofNullable(getUserById(id)).orElseGet(() -> new User(0, "Unknown"));System.out.println("Username is: " + user.getUsername());

3.4 orElseThrow

orElseThrow 与 orElse 方法的区别在于,orElseThrow 方法当 Optional 中有值的时候,返回值;没有值的时候会抛出异常,抛出的异常由传入的 exceptionSupplier 提供。

User user = Optional.ofNullable(getUserById(id)).orElseThrow(() -> new EntityNotFoundException("id 为 " + id + " 的用户没有找到"));

举一个 orElseThrow 的用途:在 SpringMVC 的控制器中,我们可以配置统一处理各种异常。查询某个实体时,如果数据库中有对应的记录便返回该记录,否则就可以抛出 EntityNotFoundException ,处理 EntityNotFoundException 的方法中我们就给客户端返回Http 状态码 404 和异常对应的信息 —— orElseThrow 完美的适用于这种场景。

@RequestMapping("/{id}")
public User getUser(@PathVariable Integer id) {Optional<User> user = userService.getUserById(id);return user.orElseThrow(() -> new EntityNotFoundException("id 为 " + id + " 的用户不存在"));
}@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<String> handleException(EntityNotFoundException ex) {return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}

3.5 map

如果当前 Optional 为 Optional.empty,则依旧返回 Optional.empty;否则返回一个新的 Optional,该 Optional 包含的是:函数 mapper 在以 value 作为输入时的输出值。

Optional<String> username = Optional.ofNullable(getUserById(id)).map(user -> user.getUsername());System.out.println("Username is: " + username.orElse("Unknown"));

而且我们可以多次使用map操作:

Optional<String> username = Optional.ofNullable(getUserById(id)).map(user -> user.getUsername()).map(name -> name.toLowerCase()).map(name -> name.replace('_', ' '));System.out.println("Username is: " + username.orElse("Unknown"));

3.6 flatMap

flatMap 方法与 map 方法的区别在于,map 方法参数中的函数 mapper 输出的是值,然后 map 方法会使用 Optional.ofNullable 将其包装为 Optional;而 flatMap 要求参数中的函数 mapper 输出的就是 Optional。

Optional<String> username = Optional.ofNullable(getUserById(id)).flatMap(user -> Optional.of(user.getUsername())).flatMap(name -> Optional.of(name.toLowerCase()));System.out.println("Username is: " + username.orElse("Unknown"));

3.7 filter

filter 方法接受一个 Predicate 来对 Optional 中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个 Optional;否则返回 Optional.empty。

Optional<String> username = Optional.ofNullable(getUserById(id)).filter(user -> user.getId() < 10).map(user -> user.getUsername());System.out.println("Username is: " + username.orElse("Unknown"));

有了 Optional,我们便可以方便且优雅的在自己的代码中处理 null 值,而不再需要一昧通过容易忘记和麻烦的 if (object != null) 来判断值不为 null。如果你的程序还在使用 Java8 之前的 JDK,可以考虑引入 Google 的 Guava 库 —— 事实上,早在 Java6 的年代,Guava 就提供了 Optional 的实现。

4. Java9 对Optional的增强

即将在今年 7 月到来的 JDK9 中,在 Optional 类中添加了三个新的方法:

4.1 or方法
or 方法的作用是,如果一个 Optional 包含值,则返回自己;否则返回由参数 supplier 获得的 Optional

4.2 ifPresentOrElse
ifPresentOrElse 方法的用途是,如果一个 Optional 包含值,则对其包含的值调用函数 action,即 action.accept(value),这与 ifPresent 一致;与 ifPresent 方法的区别在于,ifPresentOrElse 还有第二个参数 emptyAction —— 如果 Optional 不包含值,那么 ifPresentOrElse 便会调用 emptyAction,即 emptyAction.run()

4.3 stream
stream 方法的作用就是将 Optional 转为一个 Stream,如果该 Optional 中包含值,那么就返回包含这个值的 Stream;否则返回一个空的 Stream(Stream.empty())。
举个例子,在 Java8,我们会写下面的代码:

// 此处 getUserById 返回的是 Optional<User>
public List<User> getUsers(Collection<Integer> userIds) {return userIds.stream().map(this::getUserById)     // 获得 Stream<Optional<User>>.filter(Optional::isPresent)// 去掉不包含值的 Optional.map(Optional::get).collect(Collectors.toList());
}

而有了 Optional.stream(),我们就可以将其简化为

public List<User> getUsers(Collection<Integer> userIds) {return userIds.stream().map(this::getUserById)    // 获得 Stream<Optional<User>>.flatMap(Optional::stream) // Stream 的 flatMap 方法将多个流合成一个流.collect(Collectors.toList());
}

有帮到你的点赞、收藏一下吧

需要更多教程,微信扫码即可

Optional的巧用相关推荐

  1. java中npe问题,【Java 8】巧用Optional之优雅规避NPE问题

    避之不及的 NullPointerException NPE : NullPointerException 空指针异常是最常见的Java异常之一,抛出NPE错误不是用户操作的错误,而是开发人员的错误, ...

  2. 巧用 Nginx 快速实现 HTTPS 双向认证

    1.原理 双向认证,顾名思义,客户端和服务器端都需要验证对方的身份,在建立 HTTPS 连接的过程中,握手的流程比单向认证多了几步.单向认证的过程,客户端从服务器端下载服务器端公钥证书进行验证,然后建 ...

  3. iOS 面试题--转自唐巧

    iOS 面试题(一)寻找最近公共 View 题目:找出两个 UIView 的最近的公共 View,如果不存在,则输出 nil . 分析:这其实是数据结构里面的找最近公共祖先的问题. 一个UIViewC ...

  4. 标题: 巧用curl代替ez-ipupdate更新动态dns[zt]

    标题: 巧用curl代替ez-ipupdate更新动态dns 以前在我的FC3上一直用www.3322.org上提供的ez-ipupdate做动态dns,解析家里因拨号不断改变的机器ip地址,没什么问 ...

  5. Python type hints 之 Optional,Union

    1,前言 type hint 在pep484加入,我个人觉得这种类似于类型约束的(机制)有点违背了python简单.简洁的初衷,在慢慢向c# java 这种强类型语言看齐的节奏. 不过好在不强制使用, ...

  6. PHP也玩并发,巧用curl 并发减少后端访问时间

    说明:本人源自3篇博文 http://blog.csdn.net/zuiaituantuan/article/details/7048782 首先,先了解下 php中的curl多线程函数: # cur ...

  7. Java Optional类源码解析和用法

    个人网站:http://xiaocaoshare.com/ 要求:jdk1.8以上 Optional类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get( ...

  8. 巧用Excel 2010数据透视表制作销售报表

    小刘需要根据2010-2011两年间的订单记录创建季度报表,以便分析各类图书的销售情况.面对如此庞大的订单记录,该从何下手呢? 其实最快捷的办法是使用Excel 2010创建数据透视表,以快速合并和比 ...

  9. Java8 Optional,可以这样用啊

    以下文章来源方志朋的博客,回复"666"获面试宝典 很多公众号其实都发过 Optional 的文章, 但大多文章都是介绍了 Optional 的 API 用法,却没有给出怎么正确的 ...

最新文章

  1. 拥抱对手 微软崛起或靠“云计算”业务
  2. 并发编程-26 高并发处理手段之服务降级与服务熔断 + 数据库切库分库分表
  3. 循环神经网络教程3-BP算法和梯度消失问题, Part 3 – Backpropagation Through Time and Vanishing Gradients
  4. GHOST内部错误 36000(internal error 36000)情况的解决办法
  5. php gettext 为空,PHP Gettext
  6. 【图像分割】基于matlab GUI多种阈值图像分割(带面板)【含Matlab源码 733期】
  7. 计算机学科融合信息技术,信息技术与学科教学融合课例解析
  8. 菜鸟学运筹学----引
  9. 轻文章-使用URL Rewrite实现网站伪静态
  10. 方格网提取高程点lisp_基于VBA的道路横断面高程点提取方法研究
  11. win8 计算机组策略,win8系统安装软件提示“组策略阻止了这个程序”的解决方法...
  12. k8s service nodeport
  13. MySQL B+树 BTree原理、增删改(详细)
  14. 沐神点赞!同济子豪兄精读AI经典论文,包括图像分类、目标检测、生成对抗网络、轻量化卷积神经网络等领域...
  15. 七个研究生必备高效科研网站
  16. 一个微信小程序的案例
  17. 发射功率 dBm 计算
  18. COD测定仪小故障不及时处理,可能会演变成的大问题
  19. 1 php方式实现购物车原理,PHP购物车实现的原理
  20. php用css改变字体,css怎么设置字体立体

热门文章

  1. 余承东:华为自研的麒麟A1芯片已经应用在了多款可穿戴产品中
  2. B站签约冯提莫,能否靠直播业务实现年入一百亿目标?
  3. 华为畅享10评测:4800万超清夜景 多方全能的千元实力派手机
  4. 2019胡润女企业家榜公布:碧桂园杨惠妍继续领跑
  5. 救救孩子?强制实名游戏不足四成 青少年视力保护状况堪忧
  6. 罗永浩:比起悲剧英雄 我更喜欢被当成失败的小丑
  7. iOS 13发布日期确定 苹果WWDC2019定档!
  8. fatal: protocol error: bad line length character: No s原因
  9. 轻松搞定面试中的链表题目
  10. Android音频开发(五)如何存储和解析最简单的音频wav文件