java8 新特性 -Optional的常见用法
1. Optional
一、 简介
Opitonal是java8引入的一个新类,目的是为了解决空指针异常问题。本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。
Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。但是 Optional 的意义显然不止于此。
二、Java8 之前,空指针异常判断
java在使用对象过程中,访问任何方法或属性都可能导致 NullPointerException:
比如:String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();
在这个小示例中,如果我们需要确保不触发异常,就得在访问每一个值之前对其进行明确地检查:
if (user != null) {
Address address = user.getAddress();
}if (address != null) {
Country country = address.getCountry();
}if (country != null) {
String isocode = country.getIsocode();
}if (isocode != null) {
isocode = isocode.toUpperCase();
}
为了简化这个过程,我们来看看用Optional类是怎么做的。
三、Optional的使用
1、创建Optional实例
重申一下,这个类型的对象可能包含值,也可能为空。你可以使用同名方法创建一个空的 Optional。
// 创建一个空的 Optional
Optional<User> empty = Optional.empty();
// 获取Optional的值
empty.get();
毫不奇怪,尝试访问 emptyOpt 变量的值会导致 NoSuchElementException。
你可以使用 of() 和 ofNullable() 方法创建包含值的 Optional。两个方法的不同之处在于如果你把 null 值作为参数传递进去,
of()方法会抛出NullPointerException:
User user = null;
Optional<User> user = Optional.of(user);
因此,你应该明确对象不为 null 的时候使用 of()。
如果对象即可能是 null 也可能是非 null,你就应该使用 ofNullable() 方法:
User user = null;
Optional<User> opt = Optional.ofNullable(null);
2,访问 Optional 对象的值
从 Optional 实例中取回实际值对象的方法之一是使用 get() 方法:
String name = "John";
Optional<String> opt = Optional.ofNullable(name);
assertEquals("John", opt.get());
不过,你看到了,这个方法会在值为 null的时候抛出异常。要避免异常,你可以选择首先验证是否有值:
| 方法 | 返回值 | 作用 |
|---|---|---|
| Optional.isPresent() | boolean | 当前对象为null 返回false 否则返回true |
| Optional.ifPresent(Consumer<? super T> action) | void | 当前对象为null,啥都不做,否则执行函数式接口中的内容 |
User user = new User("湖南");
Optional<User> opt = Optional.ofNullable(user);
// opt 是否为Null
System.out.println(opt.isPresent() ? "存在" : "不存在");
// 不为null时执行的操作 这里也可以写成lambda方式
opt.ifPresent(new Consumer<User>() {
@Override
public void accept(User user) {
System.out.println(user);
}
});
在我们的开发中,NullPointerException可谓是随时随处可见,为了避免空指针异常,我们常常需要进行 一
些防御式的检查,所以在代码中常常可见if(obj != null) 这样的判断。幸好在JDK1.8中,java为我们提供了
一个Optional类,Optional类能让我们省掉繁琐的非空的判断。下面先说一下Optional中为我们提供的方法。
接下来,我们来看看提供空值的方法。
3,返回默认值
| 方法 | 返回值 | 作用 |
|---|---|---|
| Optional.orElse() | User | 对象为空的时候返回默认值 |
| Optional.orElseGet() | User | 对象为空的时候返回函数式接口的返回值(需要我们定义) |
分ptional类提供了API用以返回对象值,或者在对象为空的时候返回默认值:orElse(),
如果有值则返回该值,否则返回传递给它的参数值:
User user = null;
User user1 = new User("湖南");
// 当user 为空时 返回orElse中的默认值
User result = Optional.ofNullable(user).orElse(user1);
System.out.println(result);
// 执行结果
User(address=湖南)
第二个同类型 Api 则有所不同,这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果:
也就是说,其返回的结果是由我们所创建的
User user = null;
// 当user 为空时 返回orElseGet 函数式接口中定义的返回值
User result = Optional.ofNullable(user).orElseGet(() -> new User("默认"));
System.out.println(result);
下面我们来看一个示例,突出二者的区别:
注意: 这里的Optional不是空的哦
public static void main(String[] args) {
User user = new User("湖南");
User user1 = (User) Optional.ofNullable(user).orElse(createUser("orElse"));
User result = Optional.ofNullable(user).orElseGet(() -> createUser("orElseGet"));
System.out.println(result);
}
private static User createUser(String str) {
log.info("{} 创建的对象--", str);
return new User("默认值");
}
// 执行结果
[INFO ] 2022-09-12 13:40:30,987(0) --> [main] look.word.Optional.Demo2.createUser(Demo2.java:31): orElse 创建的对象--
User(address=湖南)
User(address=湖南)
可以看到,这个示例中,两个 Optional 对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不创建 User 对象。
在执行较密集的调用时,比如调用 Web 服务或数据查询,这个差异会对性能产生重大影响。
5、返回异常 (常用)
| 方法 | 返回值 | 作用 |
|---|---|---|
| Optional.orElseThrow() | void | 它会在对象为空的时候抛出异常,而不是返回备选的值: |
除了 orElse() 和 orElseGet() 方法,Optional 还定义了 orElseThrow() API —— 它会在对象为空的时候抛出异常,而不是返回备选的值:
User result = Optional.ofNullable(user).orElseThrow( () -> new IllegalArgumentException());
这里,如果 user 值为 null,会抛出 IllegalArgumentException。
这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出 NullPointerException。
现在我们已经很好地理解了如何使用 Optional,我们来看看其它可以对 Optional 值进行转换和过滤的方法。
6、转换值
有很多种方法可以转换 Optional 的值。我们从 map() 和 flatMap() 方法开始。
先来看一个使用 map() API 的例子:
User user = new User("湖南");
String address = Optional.ofNullable(user).map(u -> u.getAddress()).orElse("默认!");
System.out.println(address.equals(user.getAddress())?"相同":"不相同");
// 执行结果 User user = new User(); 结果 为 不相同
// 相同
map() 对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional 中。这就使对返回值进行链试调用的操作成为可能 —— 这里的下一环就是 orElse()。
相比这下,flatMap() 也需要函数作为参数,并对值调用这个函数,然后直接返回结果。
下面的操作中,我们给 User 类添加了一个方法,用来返回 Optional:
User user = new User();
String address = Optional.ofNullable(user)
.flatMap(u -> Optional.ofNullable(u.getAddress()))
.orElse("默认!");
System.out.println(address.equals(user.getAddress()) ? "相同" : "不相同");
// 执行结果 User user = new User(); 结果 为 不相同
// 相同
二者区别:
简单来说: 二者返回值类型不同
- map()的返回值类型: 比如返回的是字符串 那么他的返回值类型就是字符串
- flatMap()的返回值类型:则是用Optional包裹的,我们还可以对他进行一系列操作
7、过滤值:
filter() 接受一个 Predicate 参数,返回测试结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional。
来看一个根据基本的电子邮箱验证来决定接受或拒绝 User(用户) 的示例:
User user = new User( "234");
Optional<User> result = Optional.ofNullable(user)
.filter(u -> u.getAddress() != null && u.getAddress().contains("1"));
System.out.println(result);
java8 新特性 -Optional的常见用法的更多相关文章
- Java8 新特性 Optional 类
Optional 类的简介 Optional类的是来自谷歌Guava的启发,然后就加入到Java8新特性中去了.Optional类主要就是为子决解价值亿万的错误,空指针异常. Optional ...
- JAVA8新特性Optional,非空判断
Optional java 的 NPE(Null Pointer Exception)所谓的空指针异常搞的头昏脑涨, 有大佬说过 "防止 NPE,是程序员的基本修养." 但是修养归 ...
- Java8新特性——Optional
前言 在开发中,我们常常需要对一个引用进行判空以防止空指针异常的出现.Java8引入了Optional类,为的就是优雅地处理判空等问题.现在也有很多类库在使用Optional封装返回值,比如Sprin ...
- Java8新特性--Optional
Java 8引入了一个新的Optional类.Optional类的Javadoc描述如下: 这是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会 ...
- Java8新特性Optional、接口中的默认方法与静态方法
Optional Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念 ...
- Java8新特性——Optional类的使用(有效的避免空指针异常)
OPtional类的使用 概述 到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因.以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guav ...
- java8 新特性 Optional容器类
public class Godness { private String name; public Godness() { } public Godness(String name) { this. ...
- Java8新特性 - Optional容器类
Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用null 表示一个值不存在,现在Optional 可以更好的表达这个概念.并且可以避免空指针异 ...
- 【Java8新特性】- Optional应用
Java8新特性 - Optional应用 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...
随机推荐
- UiPath文本操作Set Text的介绍和使用
一.Set Text的介绍 向输入框/文本框写入文本的一种操作 二.Set Text在UiPath中的使用 1.打开设计器,在设计库中新建一个Sequence,为序列命名及设置Sequence存放的路 ...
- bat-注册表修改win11右键风格
展开:reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32&q ...
- Linux为所有用户安装Miniconda
如果以root身份默认安装,后续普通用户再安装的话,是直接用不起来的,需要改些东西,所以在安装时最好全局安装,所有用户都可用 执行安装脚本:sudo bash Miniconda3-latest-Li ...
- 手把手带你实现基于 Vite+Vue3 的在线Excel表格系统
今天,葡萄带你了解如何基于Vite+Vue3实现一套纯前端在线表格系统. 在正式开始项目介绍之前,首先咱们首先来介绍一下Vite和Vue3. Vue3 2020年09月18日Vue.js 3.0发布, ...
- FutureTask源码深度剖析
FutureTask源码深度剖析 前言 在前面的文章自己动手写FutureTask当中我们已经仔细分析了FutureTask给我们提供的功能,并且深入分析了我们该如何实现它的功能,并且给出了使用Ree ...
- 用固态U盘让你的办公环境随身移动
有些人因为家中的电脑设备没有办公环境,或者是软件太多装起来麻烦,以及环境不同步等原因上下班总是背着电脑,其实大可不必,只要将系统装进U盘,就可以让你的办公环境随身移动.在公司时启动U盘系统工作,下班后 ...
- 活动回顾丨ALC Beijing 首场 Meetup:《开源到底有多难?》
8月16日,ALC Beijing 的首次线下沙龙活动 -- <开源到底有多难?>在微软大厦如期举行.本次沙龙主要是分享开源开发经验.探讨如何让开源项目更加茁壮成长,以及分享 ASF 管理 ...
- 一分钟安装DolphinScheduler并上手体验
一分钟安装Apache DolphinScheduler并上手体验 1 一分钟安装DolphinScheduler并上手体验 本教程基于DolphinScheduler1.3.2 2 需要准备: 一台 ...
- Redis 08 地理位置
参考源 https://www.bilibili.com/video/BV1S54y1R7SB?spm_id_from=333.999.0.0 版本 本文章基于 Redis 6.2.6 Redis 的 ...
- 【RocketMQ】事务的实现原理
事务的使用 RocketMQ事务的使用场景 单体架构下的事务 在单体系统的开发过程中,假如某个场景下需要对数据库的多张表进行操作,为了保证数据的一致性,一般会使用事务,将所有的操作全部提交或者在出错的 ...