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()));

好事定律:每件事最后都会是好事,如果不是好事,说明还没到最后。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/724079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

animation给同一个元素加多个动画

需求&#xff1a; 元素从右向左渐变滑入&#xff0c;然后再上下漂浮 代码实现&#xff1a; animation动画可连写 <style lang"less" scoped>//swipe-item里面所有animate动画延迟时间swipe-animation-delay:500ms;//animate.css动画时长animate-css-duration:…

电子电器架构刷写策略 —— 队列刷写

电子电器架构刷写策略 —— 队列刷写 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己…

关于rocky linux配置RHEL9在线镜像源

Rocky Linux 简介 Rocky Linux 是一个社区支持的企业级 Linux 发行版&#xff0c;旨在为 CentOS Stream 提供一个稳定、可预测的替代方案。它与 CentOS Linux 兼容&#xff0c;并承诺提供 10 年的支持。Rocky Linux 适用于需要一个稳定、可预测的企业级 Linux 发行版&#xff…

算法练习第十二天|二叉树的递归遍历和迭代遍历

二叉树的遍历方式有广度还有深度方式 深度优先遍历&#xff1a;先往深走&#xff0c;遇到叶子节点再往回走。 广度优先遍历&#xff1a;一层一层的去遍历。 本文写的是深度优先遍历&#xff0c;分为前序&#xff0c;中序&#xff0c;后序遍历。这里前中后&#xff0c;其实指的就…

wpf 由于尚未生成某些自定义元素,设计视图无法正确显示。

"WPF 由于尚未生成某些自定义元素&#xff0c;设计视图无法正确显示" 这个问题通常是由于 Visual Studio 设计时的限制或某些资源未正确加载导致的。以下是一些可能的解决方案&#xff1a; 1. 重新生成项目&#xff1a; 尝试重新生成整个项目&#xff0c;以确保所有…

EasyX的学习2

消息处理——漂亮的按钮(鼠标) 用到的函数 1.消息结构体变量类型&#xff1a;使用ExMessage ExMessage msg{ 0 }; 定义一个变量名为msg的ExMessage结构体变量并初始化为0 2.获取消息函数&#xff1a;peekmessage函数 //获取消息 peekmessage(&msg, EX_MOUSE); 两个参…

Freertos自学笔记1----参考正点原子视频

RTOS与裸机系统对比记忆&#xff1a; 裸机系统&#xff1a;前后台系统&#xff1b; RTOS&#xff1a;实时操作系统&#xff0c;讲究实时性&#xff1b; 裸机系统中通常我们将需要工作的函数全部放在主while(1){}中&#xff0c;所有需要工作的函数独立排列&#xff0c;然后依次…

【Linux】基本指令(中)

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:Linux ⚙️操作环境:Xshell (操作系统:CentOS 7.9 64位) 目录 man指令 cp指令 mv指令 cat指令 more指令 less指令 head指令 …

如何对酒店开展科学的定岗定编——以酒店健身房、娱乐房为例

近年来&#xff0c;随着旅游行业的快速发展&#xff0c;也带动了酒店业的兴盛。酒店的经营效益不仅受益于旅游业&#xff0c;同时也受制于旅游行业。由于旅游业存在明显的季节性差异&#xff0c;旅游旺季客流量多、淡季客流量少&#xff0c;造成人员忙闲不均的问题。酒店行业也…

Vue自定义组件实现v-model

前言 v-model 实际上就是 $emit(input) 以及 props:value 的组合语法糖。 1.封装自定义组件 要在 Vue 中实现自定义组件的 v-model 功能&#xff0c;你可以通过使用 model 选项来定义组件的 prop 和事件。以下是一个示例代码&#xff0c;演示如何实现一个自定义组件并使用 v…

gofly接口入参验证使用介绍

接口传入的参数做相关性质验证是开发中较为常用&#xff0c;gofly框架内置校验工具&#xff0c;提供开发效率&#xff0c;开发接口简单调用即可实现验证&#xff0c;下面介绍gofly框架数据验证设计思路及使用方法。 gofly框架提供了功能强大、使用便捷、灵活易扩展的数据/表单…

闰年导致的哪些 Bug

每次闰年对程序员们都是一个挑战&#xff0c;平时运行好好的系统&#xff0c;在 02-29 这一天&#xff0c;好像就会有各种毛病。 虽然&#xff0c;提前一天&#xff0c;领导们都会提前给下面打招呼。但是&#xff0c;不可避免的&#xff0c;今天公司因为闰年还是有一些小故障。…

Linux conntrack和iptables技术解析

Linux虚拟文件系统管理技术 1. netfilter解析1.1 netfilter的基础原理1.2 netfilter的相关hook 2. conntrack解析2.1 conntrack的基础原理2.2 conntrack的表记录解析 3. iptables解析3.1 iptables基础原理3.2 融合conntrack表的iptables规则 4. 疑问和思考4.1 conntrack和iptab…

医学知识和医疗应用开发交叉领域中垂类大语言模型应用相关研究

前言&#xff1a; 基于公司对LLM落地的期望&#xff0c;此proposal尚未研究完毕&#xff0c;只是简单做了一些消息整合和建议。 关于知识细节详见末尾Refs 背景&#xff1a; 随着LLM&#xff08;大语言模型&#xff09;的爆火&#xff0c;不少企业都在寻找通过LLM解决企业业…

揭秘:小红书笔记详情API如何助力电商提升营销效果

小红书是一个流行的社交电商平台&#xff0c;用户可以在上面分享购物心得、晒单、评论商品等。对于电商来说&#xff0c;了解小红书用户的行为和喜好&#xff0c;以及他们的购物决策过程&#xff0c;是提升营销效果的关键。小红书提供了笔记详情API&#xff0c;使得电商能够获取…

【学习笔记】java项目:黑马头条(day01)

文章目录 环境搭建、SpringCloud微服务(注册发现、服务调用、网关)1)课程对比2)项目概述2.1)能让你收获什么2.2)项目课程大纲2.3)项目概述2.4)项目术语2.5)业务说明 3)技术栈4)nacos环境搭建4.1)虚拟机镜像准备4.2)nacos安装 5)初始工程搭建5.1)环境准备5.2)主体结构 6)登录6.1…

Linux网络隧道协议IPIP认知(基于Linux network namespace 的 IPIP 隧道通信)

写在前面 博文内容为 Linux 隧道通信 IPIP认知内容涉及&#xff1a;ipip 介绍&#xff0c;一个 ipip 通信 Demo 以及数据帧流转分析理解不足小伙伴帮忙指正 某些人和事&#xff0c;哪怕没有缘分&#xff0c;是路边的风景&#xff0c;可是只要看一眼&#xff0c;依然会让人觉得…

高转化利器】Xinstall实现H5唤醒App,打开指定页面,轻松满足营销需求!

在移动互联网时代&#xff0c;App的拉新促活对于企业的发展至关重要。为了提升用户体验和转化率&#xff0c;Xinstall推出了一项强大的功能——H5唤醒App。通过这一功能&#xff0c;用户可以直接从Web页面拉起App&#xff0c;并在拉起过程中通过传参打开指定页面&#xff0c;满…

(自用笔记)每天一点vue3——第一天setup/defineProps

<script setup></script> setup语法糖&#xff0c;script中的所有内容相当于是在一个setup函数中执行的。并且声明的所有变量、引用的方法\组件&#xff08;组件名最好用大驼峰&#xff09;都能直接在模板字符串中使用。不再用data\method之类的方法包裹。setup引入…

QT在scrollArea中添加按钮,可滚动

添加按钮可滚动&#xff0c;同时设置按钮大小&#xff0c;代码如下 ui->setupUi(this); //在UI里面已经拖了一个scrollAreamyWidget new QWidget(this); //新建一个QWidget放在scrollArea中QVBoxLayout *layout new QVBoxLayout(…