Optional 详解
Optional 详解
- 1、Optional 介绍
- 2、创建 Optional 对象
- 3、Optional 常用方法
- 1. 判断值是否存在 — isPresent()
- 2. 非空表达式 — ifPresent()
- 3. 设置(获取)默认值 — orElse()、orElseGet()
- 4. 获取值 — get()
- 5. 过滤值 — filter()
- 6. 转换值 — map()
作为一名 Java 程序员,我真的是烦透了 NullPointerException(NPE),尽管和它熟的像一位老朋友,知道它也是迫不得已——程序正在使用一个对象,却发现这个对象的值为 null,于是 Java 虚拟机就怒发冲冠的把它抛出来当作替罪羊。
当然了,我们程序员是富有责任心的,不会坐视不管,于是就有了大量的 null 值检查。尽管有时候这种检查完全没必要,但我们已经习惯了例行公事。终于,Java 8 看不下去了,就引入了 Optional,以便于我们编写的代码不再那么刻薄呆板。
1、Optional 介绍
- Optional 类是一个可以为 null 的容器对象。如果值存在则 isPresent() 方法会返回 true,调用 get() 方法会返回该对象。
- Optional 是一个容器:它可以保存类型 T 的值,或者仅仅保存 null。Optional 提供很多有用的方法,这样我们就不用显示进行空值检测。
- Optional 类的引用很好的解决了空指针异常。
2、创建 Optional 对象
1)可以使用静态方法 empty()
创建一个空的 Optional 对象
Optional<Object> empty = Optional.empty();
System.out.println(empty); // 输出:Optional.empty
2)可以使用静态方法of()
创建一个非空的 Optional 对象
Optional<Object> opt = Optional.of("王二");
System.out.println(opt); // 输出:Optional[王二]
当然了,传递给of()
方法的参数必须是非空的,也就是说不能为 null ,否则仍然会抛出 NullPointerException。
3)可以使用静态方法ofNullable()
创建一个即可空又可非空的 Optional 对象
String name = null;
Optional<String> optOrNull = Optional.ofNullable(name);
System.out.println(optOrNull); // 输出:Optional.empty
ofNullable()
方法内部有一个三元表达式,如果参数为 null,则返回私有常量 empty;否则使用 new 关键字创建一个心的 Optional 对象——不会再抛出 NPE 异常了。
3、Optional 常用方法
1. 判断值是否存在 — isPresent()
isPresent()
方法可以判断一个 Optional 对象是否存在,如果存在,返回 true,否则返回 false。该方法取代了 obj != null 的判断
Optional<String> opt = Optional.of("王二");
System.out.println(opt.isPresent()); // 输出:trueOptional<String> optOrNull = Optional.ofNullable(null);
System.out.println(opt.isPresent()); // 输出:false
Java 11 后还可以通过方法isEmpty()
(判断值是否为空),判断与isPresent()
相反的结果
Optional<String> opt = Optional.of("王二");
System.out.println(opt.isEmpty()); // 输出:falseOptional<String> optOrNull = Optional.ofNullable(null);
System.out.println(opt.isEmpty()); // 输出:true
2. 非空表达式 — ifPresent()
ifPresent()
是 Optional 类的一个非常现代化的方法,允许我们使用函数式编程的方法执行一些代码。如果没有该方法的话,我们通常需要先通过isPresent()
方法对 Optional 对象进行判空后再执行相应的代码:
Optional<String> optOrNull = Optional.ofNullable(null);
if (optOrNull.isPresent()) {System.out.println(optOrNull.get().length());
}
而有了ifPresent()
之后,情况就完全不同了,可以直接讲 Lambda 表达式传递给该方法,代码更加简洁、直观。
Optional<String> opt = Optional.of("王二");
opt.ifPresent(x -> System.out.println(x.length()));
Java 9 后还可以通过方法ifPresentOrElse(action, emptyAction)
执行两种结果,非空时执行 action,空时执行 emptyAction。
Optional<String> opt = Optional.of("王二");
opt.ifPresentOrElse(x -> System.out.println(x.length()), () -> System.out.println("为空"));
3. 设置(获取)默认值 — orElse()、orElseGet()
有时候,我们在创建(获取) Optional 对象的时候,需要一个默认值,orElse()
和orElseGet()
方法就派上用场了。
orElse()
方法用于返回包裹在 Optional 对象中的值,如果该值不为 null ,则返回;否则返回默认值。该方法的参数类型和值的类型一致
String nullName = null;
String name = Optional.ofNullable(nullName).orElse("王二");
System.out.println(name); // 输出:王二
orElseGet()
方法与orElse()
类似,但参数类型不同。如果 Optional 对象中的值为 null,则执行参数中的函数
String nullName = null;
String name = Optional.ofNullable(nullName).orElseGet(()->"沉默王二");
System.out.println(name); // 输出:沉默王二
从输出结果以及代码的形式上来看,这两个方法极其相似,这不免引起我们的怀疑,Java 类库的设计者有必要这做吗?
假设现在有这样一个获取默认值的方法,很传统的方式。
public static String getDefaultValue() {System.out.println("www111");return "w1";}
然后通过orElse()
与orElseGet()
方法分别调用getDefaultValue()
返回默认值:
String nullName = null;
String orElse = Optional.ofNullable(nullName).orElse(getDefaultValue());
System.out.println("orElse: "+ orElse);
// 类名::方法名 是 Java 8 引入的语法,方法名后面没有 () 的,表明该方法不一定会被调用
String orElseGet = Optional.ofNullable(nullName).orElseGet(QuesRecordServiceImpl::getDefaultValue);
System.out.println("orElseGet: "+ orElseGet);System.out.println("======================");String name = "w2";
String orElse2 = Optional.ofNullable(name).orElse(getDefaultValue());
System.out.println("orElse2: "+ orElse2);
String orElseGet2 = Optional.ofNullable(name).orElseGet(QuesRecordServiceImpl::getDefaultValue);
System.out.println("orElseGet2: "+ orElseGet2);
结果如下:
咦,在 Optional 对象的值不为 null 时,orElseGet()
没有去调用getDefaultValue()
。哪个方法的性能更佳,你明白了吧?
4. 获取值 — get()
直观从语义上来看,get()
方法才是最正宗的获取 Optional 对象值的方法,但很遗憾,该方法是有缺陷的,因为假如 Optional 对象的值为 null,该方法会抛出 NoSuchElementException 异常。这完全与我们使用 Optional 类的初衷相悖。
public class GetOptionalDemo {public static void main(String[] args) {String name = null;Optional<String> optOrNull = Optional.ofNullable(name);System.out.println(optOrNull.get());}
}
这段程序在运行时会抛出异常:
尽管抛出的异常是 NoSuchElementException 而不是 NEP,但在我们看来,显然是 “五十步笑百步”。建议使用orElseGet()
方法获取 Optional 对象的值。
5. 过滤值 — filter()
filter()
方法可以传入一个 Lambda 表达式作为条件,如果表达式结果为 false,则返回一个 empty 的 Optional 对象,否则返回过滤后的 Optional 对象。
String password = "12345";
Optional<String> opt = Optional.ofNullable(password);
System.out.println(opt.filter(pwd -> pwd.length() > 6).isPresent()); // 输出:false
filter()
方法的参数类型为 Predicate(Java 8 新增的一个函数式接口),在上例中,由于 password 所以结果为 false。假设密码长度要求在 6 到 10 位之间,那么还可以再追加一个条件:
Predicate<String> len6 = pwd -> pwd.length() > 6;
Predicate<String> len10 = pwd -> pwd.length() < 10;password = "1234567";
opt = Optional.ofNullable(password);
boolean result = opt.filter(len6.and(len10)).isPresent();
System.out.println(result); // 输出:true
这次结果为 true。因为密码变成了 7 位,符合条件。想象一下,假如使用 if-else 来完成这个任务,代码该有多冗长。
6. 转换值 — map()
map()
方法可以按照一定的规则将原有 Optional 对象转换为一个新的 Optional 对象,原有的 Optional 对象不会更改。
String name = "王二";
Optional<String> nameOptional = Optional.of(name);
Optional<Integer> intOpt = nameOptional.map(String::length);System.out.println( intOpt.orElse(0)); // 输出:2
在上面这个例子中,map()
方法的入参String::length
,意味着要将原有字符串类型的 Optional 按照字符串长度重新生成一个新的 Optional 对象,类型为 Integer。
当入参也是一个 Optional 时,经过map()
转化后会形成一个 Optional<Optional< Integer >> 这种嵌套结构;但flatMap()
可以把这种嵌套结构打开:
Optional<Optional<Integer>> unFlatMap = nameOptional.map(x -> Optional.of(x.length()));
Optional<Integer> flatMap = nameOptional.flatMap(x -> Optional.of(x.length()));
好事定律:每件事最后都会是好事,如果不是好事,说明还没到最后。
相关文章:

Optional 详解
Optional 详解 1、Optional 介绍2、创建 Optional 对象3、Optional 常用方法1. 判断值是否存在 — isPresent()2. 非空表达式 — ifPresent()3. 设置(获取)默认值 — orElse()、orElseGet()4. 获取值 — get()5. 过滤值 — filter()6. 转换值 — map() 作为一名 Java 程序员&am…...
(科目三)数据库基础知识
1、基本概念 1.1 数据库 1、数据、信息和数据处理 数据是指表达信息的某种物理符号; 信息是对客观事物的反映,是为某一特定目的二提供的决策数据; 数据处理是指将数据转换成信息的过程,是对各类型的数据进行收集、整理、存储、…...

Unity性能优化篇(十) 模型优化之网格合并 Easy Mesh Combine Tool插件使用以及代码实现网格合并
把多个模型的网格合并为一个网格。可以使用自己写代码,使用Unity自带的CombineMeshes方法,也可以使用资源商店的插件,在资源商店搜Mesh Combine可以搜索到相关的插件,例如Easy Mesh Combine Tool等插件。 可大幅度减少Batches数量…...

0.8秒一张图40hx矿卡stable diffusion webui 高质极速出图组合(24.3.3)
新消息是。经过三个月的等待,SD Webui (automatic1111)终于推出了新版本1.8.0,本次版本最大的更新,可能就是pytorch更新到2.1.2, 不过还是晚了pytorch 2.2.2版。 不过这版的一些更新,在forget分支上早就实现了,所以。…...

手写分布式配置中心(四)增加实时刷新功能(长轮询)
上一篇文章中实现了短轮询,不过短轮询的弊端也很明显,如果请求的频率较高,那么就会导致服务端压力大(并发高);如果请求的频率放低,那么客户端感知变更的及时性就会降低。所以我们来看另一种轮询…...

03 | 事务隔离:为什么你改了我还看不见?
提到事务,你肯定不陌生,和数据库打交道的时候,我们总是会用到事务。最经典的例子就是转账,你要给朋友小王转 100 块钱,而此时你的银行卡只有 100 块钱。 转账过程具体到程序里会有一系列的操作,比如查询余…...

Jmeter读取与使用Redis数据
Jmeter 作为当前非常受欢迎的接口测试和性能测试的工具,在企业中得到非常广泛的使用,而 Redis 作为缓存数据库,也在企业中得到普遍使用, Redis服务和客户端安装 windows下安装 默认端口:6379 下载地址: …...
flask 支持跨域访问 非常简单的方式 flask_cors
安装 pip install -U flask-cors from flask import Flask from flask_cors import CORSapp Flask(__name__) CORS(app)app.route("/") def helloWorld():return "Hello, cross-origin-world!"参考 https://www.cnblogs.com/anxminise/p/9814326.html …...

Hololens 2应用开发系列(1)——使用MRTK在Unity中设置混合现实场景并进行程序模拟
Hololens 2应用开发系列(1)——使用MRTK在Unity中进行程序模拟 一、前言二、创建和设置MR场景三、MRTK输入模拟的开启 一、前言 在前面的文章中,我介绍了Hololens 2开发环境搭建和项目生成部署等相关内容,使我们能生成一个简单Ho…...

Newtonsoft.Json
目录 引言 1、简单使用 1.1、官方案例 1.2、JsonConvert 2、特性 2.1、默认模式[JsonObject(MemberSerialization.OptIn/OptOut)] 2.2、序列化为集合JsonArrayAttribute/JsonDictionaryAttribute 2.3、序列化该元素JsonProperty 2.4、忽略元素JsonIgnoreAttribute 2.5、…...
速卖通平台的API返回结果有哪些数据字段?
速卖通(AliExpress)作为阿里巴巴旗下的国际电商平台,提供了API接口供开发者使用,以获取商品、订单、物流等各种信息。然而,速卖通API返回的具体数据字段可能会随着API版本、接口类型以及时间的变化而有所不同。 在编写…...
C++ 标准模板库(STL)
1、vector 动态数组,可随时添加删除元素,在堆空间开辟内存。 方法含义front() 返回第一个元素O(1) back()返回最后一个元素O(1)pop_back()删除最后一个元素O(1)push_back(ele)在末尾插入元素O(1)size()返回实际元素个数O(1)clear()清除所有元素O(N)resi…...
【Javascript】设计模式之发布订阅模式
文章目录 1、现实中的发布-订阅模式2、DOM 事件3、简单的发布-订阅模式4、通用的发布-订阅模式5、先发布再订阅6、小结 发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于…...

DataLoader
import torchvision from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter# 准备的测试数据集 数据放在了CIFAR10文件夹下test_data torchvision.datasets.CIFAR10("./CIFAR10",trainFalse, transformtorchvision.transfor…...

持续集成(CICD)- Jenkins+Git+gogs综合实战(笔记二)
文章目录 七、拉取代码方法一:直接填写命令进行拉取(不建议用这种)方法二:使用源码管理拉取代码步骤一:确认环境(检查自己是否有Git插件)步骤二:构建项目时对项目的源码管理选择 Git步骤三:输入你仓库的SSH地址或者https地址,并且添加gitee的用户名和密方法一和方法二…...
VUE:key属性的作用
在 Vue.js 中,key属性的主要作用是帮助 Vue 在进行 DOM 更新时,能够更准确地识别哪些节点可以复用。 当key值发生变化时,Vue 会执行以下步骤: 1.查找旧节点:Vue 会查找虚拟 DOM 中具有旧key值的节点。 2.匹配新节点…...

linux的通信方案(SYSTEM V)
文章目录 共享内存(Share Memory)信号队列(Message Queue)信号量(semaphore) 进程间通信的核心理念:让不同的进程看见同一块资源 linux下的通信方案: SYSTEM V 共享内存(Share Memory) 特点:1.共享内存是进程见通信最…...
VUE 入门及应用 ( 路由 router )
6.前端路由 router Vue Router | Vue.js 的官方路由 (vuejs.org) 官方地址 : https://router.vuejs.org/zh/ 6.1.基本配置 6.1.0.准备 MyPage.vue 创建 用于测试 vue文件 ../views/MyPage.vue <template><div><h1>MyPage</h1></div> </…...

SpringBoot集成RocketMQ
RocketMQ是一个纯Java、分布式、队列模型的开源消息中间件,前身是MetaQ,是阿里参考Kafka特点研发的一个队列模型的消息中间件,后开源给apache基金会成为了apache的顶级开源项目,具有高性能、高可靠、高实时、分布式特点。 环境搭…...
【Web】关于FastJson反序列化开始前的那些前置知识
目录 FastJson介绍 FJ序列化与反序列化方法 关于反序列化三种方式的关系与区别 FastJson反序列化漏洞原理通识 关于getter&setter FastJson介绍 FastJson(快速JSON)是一个Java语言编写的高性能、功能丰富且易于使用的JSON解析和序列化库。它由…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...