Java 8 到 Java 21 系列之 Optional 类型:优雅地处理空值(Java 8)
Java 8 到 Java 21 系列之 Optional 类型:优雅地处理空值(Java 8)
系列目录
- Java8 到 Java21 系列之 Lambda 表达式:函数式编程的开端(Java 8)
- Java 8 到 Java 21 系列之 Stream API:数据处理的新方式(Java 8)
- Java 8 到 Java 21 系列之 Optional 类型:优雅地处理空值(Java 8)
- Java 8 到 Java 21 系列之 新日期时间 API:精确的时间管理(Java 8) 更新中
- Java 8 到 Java 21 系列之 模块化系统:构建模块化的 Java 应用(Java 9) 更新中
- Java 8 到 Java 21 系列之 JShell:即时运行 Java 代码(Java 9) 更新中
- Java 8 到 Java 21 系列之 局部变量类型推断:var 关键字的妙用(Java 10) 更新中
- Java 8 到 Java 21 系列之 HTTP Client API:现代网络通信的基础(Java 11) 更新中
- Java 8 到 Java 21 系列之 ZGC:低延迟垃圾收集器的秘密(Java 11) 更新中
- Java 8 到 Java 21 系列之 Switch 表达式的进化(Java 12) 更新中
- Java 8 到 Java 21 系列之 文本块:轻松管理多行字符串(Java 13) 更新中
- Java 8 到 Java 21 系列之 instanceof 模式匹配:简化类型检查(Java 14) 更新中
- Java 8 到 Java 21 系列之 Records:数据类的全新体验(Java 14) 更新中
- Java 8 到 Java 21 系列之 密封类:限制继承的艺术(Java 15) 更新中
- Java 8 到 Java 21 系列之 外部函数与内存 API:无缝集成本地代码(Java 17) 更新中
- Java 8 到 Java 21 系列之 Sealed Classes 正式登场:增强类型安全性(Java 17) 更新中
- Java 8 到 Java 21 系列之 强封装 JDK 内部 API:保护你的应用程序(Java 17) 更新中
- Java 8 到 Java 21 系列之 增强的伪随机数生成器:更高质量的随机数(Java 17) 更新中
- Java 8 到 Java 21 系列之 虚拟线程:并发编程的新纪元(Java 21) 更新中
- Java 8 到 Java 21 系列之 分代 ZGC 优化:迈向更高性能(Java 21) 更新中
- Java 8 到 Java 21 系列之 序列集合 API:简化集合操作(Java 21) 更新中
摘要与引言
在软件开发的实践中,空指针异常(NullPointerException)是开发者常常遇到的问题之一。这类异常往往会导致程序崩溃,尤其是在大型系统中定位问题所在会变得非常棘手。为了帮助开发者更优雅地处理可能为空的值,Java 8 引入了 Optional 类型,这一特性极大地改善了代码的健壮性和可读性。
1 什么是 Optional
Optional<T> 是一个容器类,它可以包含一个非空值或者不包含任何值(即空值)。它的主要目的是提供一种更加安全和清晰的方式来处理可能为空的值,从而减少空指针异常的风险。
1.1 空指针异常演示
下面的例子展示了未使用 Optional 时可能出现的空指针异常。
/*** Optional单元测试案例** @author JunLiang*/
@DisplayName("Optional单元测试案例")
public class OptionalTest {@DisplayName("空指针测试")@Testpublic void nullPointerTest() {UserService userService = new UserService();User user = userService.getUserById(1L);System.out.println(user.getName()); // 可能抛出NullPointerException}class User {private String name;public User(String name) {this.name = name;}public String getName() {return name;}}class UserService {public User getUserById(Long id) {// 假设这里查询数据库,如果找不到用户则返回nullreturn null;}}}
直接运行单元测试示例报空指针异常

1.2 使用 Optional 处理
现在我们将上面的示例修改为使用 Optional 来避免空指针异常。
当查询对应的用户为空时,给用户名默认值guest
/*** Optional单元测试案例** @author JunLiang*/
@DisplayName("Optional单元测试案例")
public class OptionalTest {@DisplayName("空指针测试 - 使用Optional改进")@Testpublic void nullPointerTestWithOptional() {UserService userService = new UserService();// 如果用户为空,则提供默认值 "Guest"Optional<User> optionalUser = Optional.ofNullable(userService.getUserById(1L));String userName = optionalUser.map(User::getName).orElse("Guest");// 打印用户名或默认值System.out.println("默认用户名: " + userName);}class User {private String name;public User(String name) {this.name = name;}public String getName() {return name;}}class UserService {public User getUserById(Long id) {// 假设这里查询数据库,如果找不到用户则返回nullreturn null; // 为了演示,总是返回null}}
}
执行结果

当查询对应的用户为空时,给用配合try捕获异常进行报错提示
/*** Optional单元测试案例** @author JunLiang*/
@DisplayName("Optional单元测试案例")
public class OptionalTest {@DisplayName("空指针测试 - 使用Optional改进")@Testpublic void nullPointerTestWithOptional() {UserService userService = new UserService();// 如果用户为空,则抛出自定义异常try {// 使用Optional包装可能为空的返回值Optional<User> optionalUser = Optional.ofNullable(userService.getUserById(1L));// 尝试获取用户名,如果用户为空则抛出自定义异常String userName = optionalUser.map(User::getName).orElseThrow(() -> new RuntimeException("用户不存在"));// 打印用户名System.out.println("用户名: " + userName);} catch (RuntimeException e) {// 捕获运行时异常并打印日志System.out.println("捕获到运行时异常: " + e.getMessage());}}class User {private String name;public User(String name) {this.name = name;}public String getName() {return name;}}class UserService {public User getUserById(Long id) {// 假设这里查询数据库,如果找不到用户则返回nullreturn null; // 为了演示,总是返回null}}
}
执行结果

通过上述介绍可以看出,Optional 提供了一种优雅的方式处理潜在的空值。在实际项目中,我们可以在方法返回值、数据传输对象(DTO)、以及链式调用等场景下充分利用 Optional 来提高代码质量。
例如,在服务层方法返回用户信息时,可以返回 Optional<User> 而不是直接返回 User,这样可以明确表达返回值可能是空的意图,并且鼓励调用方考虑如何处理这种情况。
2 常见Optional使用场景
2.1 创建 Optional 对象
- 有值的情况:当你确定某个变量不是
null时,可以使用Optional.of()。Optional<String> nonNullOptional = Optional.of("Hello"); - 可能为空的情况:当你不确定某个变量是否为
null时,应该使用Optional.ofNullable()。String nullableValue = null; Optional<String> nullableOptional = Optional.ofNullable(nullableValue); - 无值的情况:当需要表示没有值时,可以使用
Optional.empty()。Optional<String> emptyOptional = Optional.empty();
2.2 检查是否存在值
- 使用
isPresent()或者 Java 11 引入的isEmpty()方法来检查Optional是否包含值。if (nonNullOptional.isPresent()) {System.out.println("Value is present: " + nonNullOptional.get()); }
2.3 执行动作如果存在值
- 使用
ifPresent()方法在Optional包含值时执行一个操作。nonNullOptional.ifPresent(value -> System.out.println("Value is present: " + value));
2.4 获取值或默认值
- 使用
orElse()提供一个默认值,在Optional为空时返回该默认值。String result = nullableOptional.orElse("Default Value"); - 使用
orElseGet()提供一个 Supplier 来延迟计算默认值。String computedResult = nullableOptional.orElseGet(() -> computeDefaultValue());
2.5. 抛出异常
- 使用
orElseThrow()在Optional为空时抛出异常。String value = nullableOptional.orElseThrow(() -> new IllegalArgumentException("Value not present"));
2.6 转换值
- 使用
map()方法对Optional中的值应用一个函数。Optional<Integer> lengthOptional = nonNullOptional.map(String::length); - 使用
flatMap()方法避免嵌套的Optional结构。Optional<Optional<String>> nestedOptional = Optional.of("World").map(s -> Optional.of(s)); Optional<String> flatMapped = nestedOptional.flatMap(x -> x); // Unwraps the nested Optional
2.7 过滤值
- 使用
filter()方法根据给定条件筛选值。Optional<String> filteredOptional = nonNullOptional.filter(s -> s.startsWith("He"));
2.8. 链式调用
- 可以组合多个操作形成链式调用来简化代码。
Optional<String> result = Optional.of("hello").filter(s -> s.length() > 3).map(String::toUpperCase).orElse("DEFAULT");
这些只是 Optional 类的一些基本用法。通过合理使用这些方法,可以使代码更加简洁、安全,并且更易于理解。
总结
Optional 是 Java 8 引入的一个重要特性,它提供了一种新的方式来处理可能为空的值,减少了空指针异常的发生,同时提升了代码的可读性和维护性。通过使用 Optional,开发者可以明确地表达出某段代码或某个方法返回值可能是空的意图,并鼓励调用者考虑如何优雅地处理这些情况。
在实际应用中,合理利用 Optional 的各种方法(如 isPresent()、ifPresent()、map()、flatMap()、filter() 等),可以让我们编写出更加健壮且易于理解的代码。尤其是当涉及到链式调用或者复杂的数据处理流程时,Optional 能够有效地简化逻辑,减少不必要的嵌套和条件判断,使得代码更加简洁明了。
然而,值得注意的是,虽然 Optional 提供了诸多便利,但它并不适合所有场景。过度使用 Optional 可能会导致代码变得冗长,特别是在基本数据类型上使用 Optional 时需要特别小心,因为这可能会带来性能上的损耗。因此,在使用 Optional 时应当根据具体情况权衡利弊,确保其带来的好处超过可能的缺点。总之,Optional 是一个强大的工具,正确地使用它可以显著提高程序的健壮性和开发效率。
相关文章:
Java 8 到 Java 21 系列之 Optional 类型:优雅地处理空值(Java 8)
Java 8 到 Java 21 系列之 Optional 类型:优雅地处理空值(Java 8) 系列目录 Java8 到 Java21 系列之 Lambda 表达式:函数式编程的开端(Java 8)Java 8 到 Java 21 系列之 Stream API:数据处理的…...
py文件打包为exe可执行文件,涉及mysql连接失败
py文件打包为exe可执行文件,涉及mysql连接失败 项目场景:使用flask框架封装算法接口,并使用pyinstaller打包为exe文件。使用pyinstaller打包多文件的场景,需要自己手动去.spec文件中添加其他文件,推荐使用auto-py-to-e…...
Ubuntu 系统 Docker 中搭建 CUDA cuDNN 开发环境
CUDA 是 NVIDIA 推出的并行计算平台和编程模型,利用 GPU 多核心架构加速计算任务,广泛应用于深度学习、科学计算等领域。cuDNN 是基于 CUDA 的深度神经网络加速库,为深度学习框架提供高效卷积、池化等操作的优化实现,提升模型训练…...
win10彻底让图标不显示在工具栏
关闭需要不显示的软件 打开 例此时我关闭了IDEA的显示 如果说只是隐藏,鼠标拖动一个道理 例QQ 如果说全部显示不隐藏...
Java服务端性能优化:从理论到实践的全面指南
目录 引言:性能优化的重要性 用户体验视角 性能优化的多维度 文章定位与价值 Java代码层性能优化方案 实例创建与管理优化 单例模式的合理应用 批量操作策略 并发编程优化 Future模式实现异步处理 线程池合理使用 I/O性能优化 NIO提升I/O性能 压缩传输…...
人脸识别和定位别的签到系统
1、功能 基于人脸识别及定位的宿舍考勤管理小程序 (用户:宿舍公告、宿舍考勤查询、宿舍考勤(人脸识别、gps 定 位)、考勤排行、请假申请 、个人中心 管理员:宿舍管理、宿舍公告管理 学生信息管理、请假审批、发布宿舍…...
基于YOLOv8的热力图生成与可视化:支持自定义模型与置信度阈值的多维度分析
目标检测是计算机视觉领域的重要研究方向,而YOLO(You Only Look Once)系列算法因其高效性和准确性成为该领域的代表性方法。YOLOv8作为YOLO系列的最新版本,在目标检测任务中表现出色。然而,传统的目标检测结果通常以边…...
echarts+HTML 绘制3d地图,加载散点+散点点击事件
首先,确保了解如何本地引入ECharts库。 html 文件中引入本地 echarts.min.js 和 echarts-gl.min.js。 可以通过官网下载或npm安装,但这里直接下载JS文件更简单。需要引入 echarts.js 和 echarts-gl.js,因为3D地图需要GL模块。 接下来是HTM…...
Design Compiler:库特征分析(ALIB)
相关阅读 Design Compilerhttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 简介 在使用Design Compiler时,可以对目标逻辑库进行特征分析,并创建一个称为ALIB的伪库(可以被认为是缓存)&…...
便携式雷达信号模拟器 —— 打造实战化电磁环境的新利器
在现代战争中,雷达信号的侦察与干扰能力直接关系到作战的成败。为了提升雷达侦察与干扰装备的实战能力,便携式雷达信号模拟器作为一款高性能设备应运而生,为雷达装备的训练、测试和科研提供了不可或缺的支持。 核心功能 便携式雷达信号模拟…...
TypeScript工程集成
以下是关于 TypeScript 工程集成 的系统梳理,涵盖基础配置、进阶优化、开发规范及实际场景的注意事项,帮助我们构建高效可靠的企业级 TypeScript 项目: 一、基础知识点 1. 项目初始化与配置 tsconfig.json 核心配置:{"compilerOptions": {"target": &…...
《P1246 编码》
题目描述 编码工作常被运用于密文或压缩传输。这里我们用一种最简单的编码方式进行编码:把一些有规律的单词编成数字。 字母表中共有 26 个字母 a,b,c,⋯,z,这些特殊的单词长度不超过 6 且字母按升序排列。把所有这样的单词放在一起,按字典…...
基于Transformer框架实现微调后Qwen/DeepSeek模型的非流式批量推理
在基于LLamaFactory微调完具备思维链的DeepSeek模型之后(详见《深入探究LLamaFactory推理DeepSeek蒸馏模型时无法展示<think>思考过程的问题》),接下来就需要针对微调好的模型或者是原始模型(注意需要有一个本地的模型文件,全量微调就是saves下面的文件夹,如果是LoRA,…...
什么是 CSSD?
文章目录 一、什么是 CSSD?CSSD 的职责 二、CSSD 是如何工作的?三、CSSD 为什么会重启节点?情况一:网络和存储都断联(失联)情况二:收到其他节点对自己的踢出通知(外部 fencing&#…...
服务器磁盘io性能监控和优化
服务器磁盘io性能监控和优化 全文-服务器磁盘io性能监控和优化 全文大纲 磁盘IO性能评价指标 IOPS:每秒IO请求次数,包括读和写吞吐量:每秒IO流量,包括读和写 磁盘IO性能监控工具 iostat:监控各磁盘IO性能,…...
CentOS Linux升级内核kernel方法
目录 一、背景 二、准备工作 三、升级内核 一、背景 某些情况需要对Linux发行版自带的内核kernel可能版本较低,需要对内核kernel进行升级。例如:CentOS 7.x 版本的系统默认内核是3.10.0,该版本的内核在Kubernetes社区有很多已知的Bug&#…...
使用MetaGPT 创建智能体(1)入门
metagpt一个多智能体框架 官网:MetaGPT | MetaGPT 智能体 在大模型领域,智能体通常指一种基于大语言模型(LLM)构建的自主决策系统,能够通过理解环境、规划任务、调用工具、迭代反馈等方式完成复杂目标。具备主动推理…...
AF3 OpenFoldMultimerDataset类解读
AlphaFold3 data_modules 模块的 OpenFoldMultimerDataset 类是 OpenFoldDataset 类的子类,专门用于 多链蛋白质(Multimer) 数据集的训练。它通过引入 AlphaFold Multimer 论文 中描述的过滤步骤,来实现多链蛋白质的训练。这个类扩展了父类的功能,特别是为了处理多链蛋白质…...
【C++】多态功能细节问题分析
多态是在不同继承关系的类对象去调用同一函数,产生了不同的行为。值得注意的是,虽然多态在功能上与隐藏是类似的,但是还是有较大区别的,本文也会进行多态和隐藏的差异分析。 在继承中要构成多态的条件 1.1必须通过基类的指针或引用…...
[CISSP] [5] 保护资产安全
数据状态 1. 数据静态存储(Data at Rest) 指存储在磁盘、数据库、存储设备上的数据,例如: 硬盘、SSD服务器、数据库备份存储、云存储 安全措施 加密(Encryption):如 AES-256 加密磁盘和数据…...
EIP-712:类型化结构化数据的哈希与签名
1. 引言 以太坊 EIP-712: 类型化结构化数据的哈希与签名,是一种用于对类型化结构化数据(而不仅仅是字节串)进行哈希和签名 的标准。 其包括: 编码函数正确性的理论框架,类似于 Solidity 结构体并兼容的结构化数据规…...
spring boot 集成redis 中RedisTemplate 、SessionCallback和RedisCallback使用对比详解,最后表格总结
对比详解 1. RedisTemplate 功能:Spring Data Redis的核心模板类,提供对Redis的通用操作(如字符串、哈希、列表、集合等)。使用场景:常规的Redis增删改查操作。特点: 支持序列化配置(如String…...
基于S函数的simulink仿真
基于S函数的simulink仿真 S函数可以用计算机语言来描述动态系统。在控制系统设计中,S函数可以用来描述控制算法、自适应算法和模型动力学方程。 S函数中使用文本方式输入公式和方程,适合复杂动态系统的数学描述,并且在仿真过程中可以对仿真…...
每日一题洛谷P8664 [蓝桥杯 2018 省 A] 付账问题c++
P8664 [蓝桥杯 2018 省 A] 付账问题 - 洛谷 (luogu.com.cn) 思路:要使方差小,那么钱不能一下付的太多,可以让钱少的全付玩,剩下还需要的钱再让钱多的付(把钱少的补上)。 将钱排序,遍历一遍&…...
迅饶科技X2Modbus网关-GetUser信息泄露漏洞
免责声明:本号提供的网络安全信息仅供参考,不构成专业建议。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我联系,我将尽快处理并删除相关内容。 漏洞描述 该漏洞的存在是由于GetUser接口在…...
【Pandas】pandas DataFrame values
Pandas2.2 DataFrame Attributes and underlying data 方法描述DataFrame.index用于获取 DataFrame 的行索引DataFrame.columns用于获取 DataFrame 的列标签DataFrame.dtypes用于获取 DataFrame 中每一列的数据类型DataFrame.info([verbose, buf, max_cols, …])用于提供 Dat…...
蓝桥杯Java B组省赛真题高频考点近6年统计分类
基础考点 考点高频难度模拟9基础枚举5基础思维4基础动态规划3基础规律2基础单位换算2基础搜索 1基础双指针1基础数学1基础哈希表1基础暴力1基础Dijkstra1基础 二分1基础 中等考点 考点高频难度动态规划6中等数学5中等枚举4中等模拟3中等思维3中等贪心3中等前缀和3中等二分2中…...
关于inode,dentry结合软链接及硬链接的实验
一、背景 在之前的博客 缺页异常导致的iowait打印出相关文件的绝对路径-CSDN博客 里 2.2.3 一节里,我们讲到了file,fd,inode,dentry,super_block这几个概念,在这篇博客里,我们针对inode和dentr…...
PandasAI:当数据分析遇上自然语言处理
数据科学的新范式 在数据爆炸的时代,传统的数据分析工具正面临着前所未有的挑战。数据科学家们常常需要花费70%的时间在数据清洗和探索上,而真正的价值创造时间却被大幅压缩。PandasAI的出现,正在改变这一现状——它将生成式AI的强大能力注入…...
Unity网络开发基础 (3) Socket入门 TCP同步连接 与 简单封装练习
本文章不作任何商业用途 仅作学习与交流 教程来自Unity唐老狮 关于练习题部分是我观看教程之后自己实现 所以和老师写法可能不太一样 唐老师说掌握其基本思路即可,因为前端程序一般不需要去写后端逻辑 1.认识Socket的重要API Socket是什么 Socket(套接字࿰…...
