Java Optional的使用实践概述
题记:不到最后时刻,千万别轻言放弃,无论结局成功与否,只要你拼博过,尽力过,一切问心无愧
Java 8是Java自Java 5(发布于2004年)之后的最重要的版本。这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。
Optional类是Java8为了解决null值判断问题,借鉴google guava类库的Optional类而引入的一个同名Optional类,本文将讲述Optional类的使用与常用方法概述。
** | 你可能需要 |
---|---|
CSDN | 网易云课堂教程 |
掘金 | EDU学院教程 |
知乎 | Flutter系列文章 |
1 为什么要设计Optional?
在 Java 开发中,通常会使用 if-else 逻辑判断来解决 NullPointerException 问题,当有对象模型嵌套过多时,就会因过多的 if-else 判断而形成代码累赘。
使用Optional类可以避免显式的null值判断(null的防御性检查),避免因过多的 if-else 判断而形成的代码累赘。
通过使用 Optional 可减少代码中的判空,实现函数式编程。
2 Optional 的基本使用
一个实际的应用场景就是需要获取用户的地区 ID 信息,传统的获取方法如下代码清单2-1所示:
//代码清单 2-1
//获取用户的地区 code
publish String getUserCountryCode(UserInfor user){String countryCode = "";if (user != null) {Address address = user.getAddress();if (address != null) {Country country = address.getCountry();if (country != null) {String code = country.getCountryCode();if (code != null) {countryCode = code.toUpperCase();}}}}return countryCode ;
}
代码清单 2-1 通过 if-else 重重校验可避免在调用过程中因某个对象为 null 而导致的 NullPointerException ,通过 Optional 类的函数式编程来实现同样的效果 如下代码清单 2-2所示 :
// 代码清单 2-2public String getUserCountryCodByOptional(UserInfor user) {return Optional.ofNullable(user).map(c -> c.getAddress()).map(r -> r.getCountry()).map(u -> u.getCountryCode()).orElseThrow(() -> new IllegalArgumentException(" 无法获取到新的值")).toUpperCase();}
Tips
双冒号:与 箭头函数->,是Java8的lambda表达式,就是匿名函数,如下代码清单 2-3中的使用。
// 代码清单 2-3public void test(){///新建集合List<String> list = new ArrayList();///模拟数据for (int i = 0; i < 10; i++) {list.add("测试数据 "+i);}//第一种 for循环for (int i = 0; i < list.size(); i++) {//获取到 list 中对应索引的值String s = list.get(i);}//第二种 增强forfor (String s: list) {//s 即为获取到的list中的值}//第三种 使用lambda表达式以及函数操作符 ->list.forEach((s) -> System.out.println(s));//第四种 Java8中使用双冒号::操作符完成list.forEach(System.out::println);}
在 代码清单 2-2中所求的效果也可以使用 双冒号来实现,如下代码清单 2-4 所示:
// 代码清单 2-4public String getUserCountryCodByOptional2(UserInfor user) {return Optional.ofNullable(user).map(UserInfor::getAddress).map(Address::getCountry).map(Country::getCountryCode).orElseThrow(() -> new IllegalArgumentException(" 无法获取到新的值")).toUpperCase();}
3 Optional 的简述
在上述代码清单中通Optional的使用,很优雅的达到函数式编程效果,现有总结以下结论。
3.1 Optional 对象创建
在使用 Optional 时首先要创建 Optional 对象,Optional类的两个构造方法都是private型的,因此类外部不能显示的使用new Optional()的方式来创建Optional对象。
可通过Optional类提供的三个静态方法empty()、of(T value)、ofNullable(T value)来创建Optinal对象,示例如下
// 第一种 创建一个包装对象值为空的Optional对象 一般不使用Optional<String> optStr = Optional.empty();// 第二种 创建包装对象值非空的Optional对象Optional<String> optStr1 = Optional.of("optional");// 第三种 创建包装对象值允许为空的Optional对象Optional<String> optStr2 = Optional.ofNullable(null);
第二种方式 通过 of 方法为非null的值创建一个Optional。of方法通过工厂方法创建Optional类。需要注意的是,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException 。
第三种方式 ofNullable 为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。
3.2 map 、flatMap 、filter
Optional 的 map 方法用来获取 Optional 中的值,Optional 也提供了 get方法来获取其中的值。
Optional 的 map 方法调用,Optional 如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
简单的描述就是通过map方法从Optional对象中提取和转换值。
public void testMap(){// 第二种 创建包装对象值非空的Optional对象Optional<String> optStr1 = Optional.of(" 测试 map 方法数据");///获取 optStr1 中的值Optional<String> stringOptional = optStr1.map((value) -> value);///optStr1 有值 所以输出的是 optionalSystem.out.println(stringOptional.orElse("orElse输出的内容"));}
单元测试效果如下图所示
flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional,目前笔者还没有应用到实际业务场景中。
filter 方法中如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。
3.3 orElse、orElseGet、orElseThrow方法
orElse方法,对应的 Optional 如果有值则将其返回,否则返回指定的其它值。
orElseGet与orElse方法类似,区别在于得到的默认值,orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值 。
orElseThrow如果有值则将其返回,否则抛出supplier接口创建的异常,在orElseThrow中我们可以传入一个lambda表达式或方法,如果值不存在来抛出异常。
public void testOrElse(){// 第一种 创建一个包装对象值为空的Optional对象Optional<String> optStr = Optional.empty();//optStr 无值 所以输出的是 orElse中的内容 "测试 orelse "//orElse 方法接收的参数是字符串System.out.println("测试1 "+optStr.orElse("测试 orelse "));// orElseGet 方法接收的是一个函数方法System.out.println("测试2 "+optStr.orElseGet(()->"测试 orElseGet "));// orElseGet 方法接收的是一个函数方法 返回值是一个 ThrowableSystem.out.println("测试3 "+optStr.orElseThrow(()-> new IllegalArgumentException("空值")));// 第二种 创建包装对象值非空的Optional对象Optional<String> optStr1 = Optional.of("optional");///optStr1 有值 所以输出的是 optionalSystem.out.println(optStr1.orElse("orElse输出的内容"));}
单元测试效果如下图所示:
4 其他
Java 9 为 Optional 类添加了三个方法:or()、ifPresentOrElse() 和 stream()。
4.1 or 方法
or 方法,如果值存在,返回 Optional 指定的值,否则返回一个预设的值。
4.2 stream 方法
stream 方法的作用就是将 Optional 转为一个 Stream,如果该 Optional 中包含值,那么就返回包含这个值的 Stream,否则返回一个空的 Stream。
4.3 ifPresentOrElse 方法
在 java8 中,使用 ifPresent 方法来替代传统的 if(user != null)判断,未提供支持 if (user != null) else { // xxx}的操作,也就是在Java8中Optional 类 ifPresent 方法没有对else的操作提供支持。
在java9 中 ifPresentOrElse 方法就相当于是 if (user != null) else { // xxx}的操作。
public void test(UserInfor user) {Optional.ofNullable(user).ifPresentOrElse(u -> {//当user 不为 null 时执行这里user.getName();user.getAge();}, () -> {//当user 为null 时执行这里System.err.println("user 对象为null");});
}
Java Optional的使用实践概述相关推荐
- java Optional操作
目录 Optional对象的创建 isPresent()和isEmpty()判空处理 ifPresent()和ifPresentOrElse()的条件动作 Optional对象中获取值 orElse( ...
- Java Optional容器判空处理
Java Optional容器判空处理 1. Java判空概述 2. Java判空方式 2.1 普通判空方式 2.2 Optional判空方式 1. Java判空概述 Java判空方式有很多多,可以i ...
- java查询枚举_查找Java枚举的最佳实践
查找Java枚举的最佳实践 我们有一个REST API,客户端可以在其中提供表示Java Enums中服务器上定义的值的参数. 因此,我们可以提供一个描述性错误,我们将此valueOf(..)方法添加 ...
- 编写高性能Java代码的最佳实践
编写高性能Java代码的最佳实践 摘要:本文首先介绍了负载测试.基于APM工具的应用程序和服务器监控,随后介绍了编写高性能Java代码的一些最佳实践.最后研究了JVM特定的调优技巧.数据库端的优化和架 ...
- MIT Graph实践概述
MIT Graph实践概述 Features功能 • iCloud Support • Multi Local & Cloud Graphs • Thread Safe • Store Any ...
- 《编译与反编译技术实战》——第2章编译器实践概述
本节书摘来自华章社区<编译与反编译技术实战>一书中的第2章编译器实践概述,作者刘晓楠 陶红伟 岳 峰 戴超,更多章节内容可以访问云栖社区"华章社区"公众号查看 第2章 ...
- Java Bean Validation 最佳实践
<h1 class="postTitle"><a id="cb_post_title_url" class="postTitle2& ...
- JVM内存管理------JAVA语言的内存管理概述
转载自 JVM内存管理------JAVA语言的内存管理概述 引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上 ...
- java 8入门与实践_30个Java入门技巧和最佳实践
java 8入门与实践 Java是最流行的编程语言之一-无论是Win应用程序,Web应用程序,移动,网络,消费电子产品,机顶盒设备,Java随处可见. 在Java上运行的设备超过30亿. 据Oracl ...
最新文章
- pytorch torch.norm(input, p=2) → float、torch.norm(input, p, dim, out=None) → Tensor(求范数)
- el-drawer点击的时候为什么有边框_别再纠结背景墙边框的材料,这4种线条边框便宜又实用,简洁大方...
- LOL手游超燃测试好评如潮,没拿到资格不用急,期待一手不删档
- 华尔街英语学习软件_华尔街英语核心课程功能升级 让学员学习之旅更高效
- 5部适合学英语的动画电影,快和孩子一起看!
- 渗透测试入门15之常见端口安全测试
- capjoint一些生成文件的解释
- 【原创】.NET读写Excel工具Spire.Xls使用(5)重量级的Excel图表功能
- 关于php聊天室的实现方法,PHP聊天室简单实现
- Win10如何设置护眼模式?
- 【Code】8位编程语言的创始人,你知道几位?
- 2018年国考行测错题集(省级)
- Java SimpleDateFormat.setLenient(boolean lenient)方法使用
- etc的常见算法_几个常用算法的适应场景及其优缺点(非常好)
- 这所“南方小镇”藏着雅居乐陈卓林描绘的“第二人生”
- 【 SAP消息号BS013】
- 快速解读Nor Flash Datasheet
- Hadoop生态系统官网、下载地址、文档
- 如何看linux是arm还是amd_如何确定真性分手还是假性分手?看这六个判断标准
- 超链接 a href 提交表单通过post方式