[Java SE]Java版本特性解读:java.util.Optional [JDK1.8-]
1 概述
本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空(null/empty)。
Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。但是 Optional 的意义显然不止于此。
我们从一个简单的用例开始。在 Java 8 之前,任何访问对象方法或属性的调用都可能导致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();
}
}
}
}
2 样例源码
你看到了,这很容易就变得冗长,难以维护。
为了简化这个过程,我们来看看用 Optional 类是怎么做的。从创建和验证实例,到使用其不同的方法,并与其它返回相同类型的方法相结合,下面是见证Optional 奇迹的时刻。
WithoutOptionalTest
package test.java.util;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;
/**
* @create-time 2022/12/29 11:00
* @description 没有 Optional 会有什么问题?
* 我们来模拟一个实际的应用场景。
* 小王第一天上班,领导老马就给他安排了一个任务,要他从数据库中根据会员 ID 拉取一个会员的姓名,然后将姓名打印到控制台。
* 虽然是新来的,但这个任务难不倒小王,于是他花了 10 分钟写下了本段代码(WithoutOptionalTest)
* @reference-doc
* [1] 干货,一文彻底搞懂 Java 的 Optional - CSDN - https://blog.csdn.net/qing_gee/article/details/104767082
*/
@Slf4j
public class WithoutOptionalTest {
/**
* 由于当前 ID 的会员不存在,故 getMemberByIdFromDB() 返回了 null 来作为没有获取到该会员的结果。
* 意味着:在打印会员姓名的时候要先对 mem 判空;否则,就会抛出 NPE 异常。
* 不信?让小王把 if (mem != null) 去掉试试,控制台立马打印错误堆栈给你颜色看看。
*/
@Test
public void withoutOptionalTest(){
Member mem = getMemberByIdFromDB();
if (mem != null) {
log.info("member.name: {}", mem.getName());
}
Assert.assertTrue(true);
}
public static Member getMemberByIdFromDB() {
// DB查询结果:当前 ID 的会员不存在
return null;
}
class Member {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
OptionalTest
package test.java.util;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* @create-time 2022/12/29 10:59
* @description Optional 是如何解决这个问题的?
* 小王把代码提交后,就兴高采烈地去找老马要新的任务了。
* 本着虚心学习的态度,小王请求老马看一下自己的代码,于是老王就告诉他应该尝试一下 Optional,可以避免没有必要的 null 值检查。
* 现在,让我们来看看小王是如何通过 Optional 来解决上述问题的。
* @reference-doc
* [1] 干货,一文彻底搞懂 Java 的 Optional - CSDN - https://blog.csdn.net/qing_gee/article/details/104767082
*/
@Slf4j
public class OptionalTest {
/**
* getMemberByIdFromDB() 方法返回了 Optional<Member> 作为结果,这样就表明 Member 可能存在,也可能不存在,这时候就可以:
* 在 Optional 的 ifPresent() 方法中使用 Lambda 表达式来直接打印结果。
*
* Optional 之所以可以解决 NPE 的问题,是因为:它明确的告诉我们,不需要对它进行判空。它就好像十字路口的路标,明确地告诉你该往哪走。
*/
@Test
public void withOptionalTest(){
Optional<Member> optional = getMemberByIdFromDB();
optional.ifPresent(mem -> {
log.debug("member.name: {}", mem.getName());
});
log.debug("optional.isPresent : {}", optional.isPresent());
log.debug("optional.get() : {}", optional.get());
optional = Optional.empty();
Member member = optional.orElse(new Member("optional 为空时设置的默认会员信息"));
log.debug("member : {}", member);
//如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
//optional.orElseThrow(() -> { return new RuntimeException("optional为空时出现异常!"); });
Assert.assertTrue(true);
}
/**
* ofNullable() 方法内部有一个三元表达式:
* 如果为参数为 null,则返回私有常量 EMPTY;
* 否则,使用 new 关键字创建了一个新的 Optional 对象——不会再抛出 NPE 异常了。
*/
@Test
public void ofNullableTest(){
//true
List<Member> list = Collections.EMPTY_LIST;
Optional<List<Member>> optionalList = Optional.ofNullable(list);
boolean present = optionalList.isPresent();
log.debug("present : {}", present);
Assert.assertTrue(true);
}
@Test
public void createOptionalObject01(){
//可以使用静态方法 empty() 创建一个空的 Optional 对象
Optional<String> empty = Optional.empty();
log.debug(empty.toString()); // 输出:Optional.empty
String str = null;
Optional<String> optionalStr = Optional.ofNullable(str);
boolean isPresent2 = optionalStr.isPresent();
log.debug("optionalStr : {}", optionalStr); // 输出:Optional.empty
log.debug("isPresent2 : {}", isPresent2); // 输出:false
Assert.assertTrue(true);
}
@Test
public void createOptionalObject02(){
//可以使用静态方法 of() 创建一个非空的 Optional 对象
Optional<String> opt = Optional.of("沉默王二");
log.debug(opt.toString()); // 输出:Optional[沉默王二]
//当然了,传递给 of() 方法的参数必须是非空的,也就是说不能为 null,否则仍然会抛出 NullPointerException。
// String name = null;
// Optional<String> optnull = Optional.of(name);// java.lang.NullPointerException
Assert.assertTrue(true);
}
@Test
public void createOptionalObject03(){
String name = null;
Optional<String> optOrNull = Optional.ofNullable(name);
log.debug("optOrNull : {}", optOrNull); // 输出:Optional.empty
Assert.assertTrue(true);
}
@Test
public void OrElseTest(){
// 有时候,我们在创建(获取) Optional 对象的时候,需要一个默认值,orElse() 和 orElseGet() 方法就派上用场了。
// orElse() 方法用于返回包裹在 Optional 对象中的值,如果该值不为 null,则返回 原本的值;否则返回默认值。该方法的参数类型和值得类型一致。
String nullName = null;
String name = Optional.ofNullable(nullName).orElse("沉默王二");
log.debug("name : {}", name); // 输出:沉默王二
String nullName2 = "hello";
String name2 = Optional.ofNullable(nullName2).orElse("沉默王二");
log.debug("name2 : {}", name2); // 输出:hello
Assert.assertTrue(true);
}
@Test
public void orElseGetTest(){
//orElseGet() 方法与 orElse() 方法类似,但参数类型不同。如果 Optional 对象中的值为 null,则执行参数中的函数。
String nullName = null;
String name = Optional.ofNullable(nullName).orElseGet(()-> { return "沉默王二"; });
log.debug("name : {}", name); // 输出:沉默王二
Assert.assertTrue(true);
}
public static Optional<Member> getMemberByIdFromDB() {
boolean hasName = true;
if (hasName) {
return Optional.of(new Member("沉默王二"));
}
return Optional.empty();
}
}
class Member {
private String name;
public Member(String name) {
this.name = name;
}
public String getName() {
return name;
}
// getter / setter
@Override
public String toString() {
return "Member{" +
"name='" + name + '\'' +
'}';
}
}
X 参考文献
[Java SE]Java版本特性解读:java.util.Optional [JDK1.8-]的更多相关文章
- Java SE 8 新增特性
Java SE 8 新增特性 作者:Grey 原文地址: Java SE 8 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...
- Java SE 9 新增特性
Java SE 9 新增特性 作者:Grey 原文地址: Java SE 9 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...
- Java SE 10 新增特性
Java SE 10 新增特性 作者:Grey 原文地址:Java SE 10 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 11 新增特性
Java SE 11 新增特性 作者:Grey 原文地址:Java SE 11 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 12 新增特性
Java SE 12 新增特性 作者:Grey 原文地址:Java SE 12 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 13 新增特性
Java SE 13 新增特性 作者:Grey 原文地址:Java SE 13 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 16 新增特性
Java SE 16 新增特性 作者:Grey 原文地址:Java SE 16 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 17 新增特性
Java SE 17 新增特性 作者:Grey 原文地址:Java SE 17 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 19 新增特性
Java SE 19 新增特性 作者:Grey 原文地址: 博客园:Java SE 19 新增特性 CSDN:Java SE 19 新增特性 源码 源仓库: Github:java_new_featu ...
- Java SE 6 新特性: Java DB 和 JDBC 4.0
http://www.ibm.com/developerworks/cn/java/j-lo-jse65/index.html 长久以来,由于大量(甚至几乎所有)的 Java 应用都依赖于数据库,如何 ...
随机推荐
- 记一次pushgateway因文件句柄数太多未回收的问题
1. 问题描述: Flink上报metrics到pushGateway,pushGwateway因打开在多文件而拒绝Flink TaskManager上报数据的连接.查看pushGateway的日志如 ...
- React中的CSS模块
CSS模块 使用步骤: 1.新建一个XXX.moudle.css文件 2.在组件中引入css impor classes(变量) fro ...
- 小梅哥课程学习——串口发送应用之发送数据(可在vivado中仿真出现正确波形)
//1.底层代码源代码发送10位数据 module uart_pr( clk, reset_n, send_go, data, baud_set, tx_done, uart_tx ); input ...
- CMMI的软件工程13-16章读书笔记
一.软件测试 软件测试是为了发现程序中的错误而执行的过程.测试只能证明软件有错,而不能保证软件程序没错. 1. 软件版本 Alpha版 公司内测版本 Beta版 对外公测版本 发布版 正式发布版本 ...
- jquery的ajax方法获取不到return返回值
/** 2 * 方式:(1)同步调用 (2)在ajax函数中return值 3 * 结果:返回 1.未成功获取返回值 4 * 失败原因:ajax内部是一个或多个定义的函数,ajax中return返回值 ...
- 8.Vuex状态管理
一.Vuex 概述 1.1 组件之间共享数据的方式 父传子: v-bind 属性绑定 子传父: v-on 事件绑定 兄弟组件之间共享数据: EventBus $on 接收数据的那个组件 (数据接收方) ...
- 2020/03/25 CSS相关知识点
2020-03-25 16:35:03 又是一个风和日丽的下午!今天的内容比较多 真是令人头大 ,手速又慢所以缺的可能比较多,而且这东西还是多靠实践为好. 文件下载地址: https://share. ...
- 【javascript】关于 canvas.toDataURL()
在工作中遇到了奇怪的问题,在此记录. 一.定义 canvas.toDataURL()方法是返回一个包含图片展示的 数据URL.可以使用 type 参数其类型,默认为 PNG格式,图片的分辨率为96dp ...
- mysql安装调试
mysql安装 1.下载mysql的压缩包 tar -xvzf mysql-5.6.38-linux-glibc2.12-i686.tar.gz2.安装之后密码是随机的,所以我们需要重新修改密码: [ ...
- vuforia 打包IOS 第一次启动正常, 删掉过程重新启动初始化失败。
我使用的是2019.4.17版本,降级到2019.2.17问题解决