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()); // 输出:true

Optional<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()); // 输出:false

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ISP基础概述

原文来自ISP 和摄像头基本知识 本文主要介绍ISP&#xff0c;以供读者能够理解该技术的定义、原理、应用。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;计算机杂记 &#x1f380;CSDN主页 发狂的小花 &#x1f3…

【短时交通流量预测】基于小波神经网络WNN

课题名称&#xff1a;基于小波神经网络的短时交通流量预测 版本时间&#xff1a;2023-04-27 代码获取方式&#xff1a;QQ&#xff1a;491052175 或者 私聊博主获取 模型简介&#xff1a; 城市交通路网中交通路段上某时刻的交通流量与本路段前几个时段的交通流量有关&#x…

登录校验-过滤器-拦截器

会话技术 会话&#xff1a;用户打开浏览器&#xff0c;访问Wb服务器的资源&#xff0c;会话建立&#xff0c;直到有一方断开连接&#xff0c;会话结束。在一次会话中可以包含多次请求和响应。 会话跟踪&#xff1a;一种维护浏览器状态的方法&#xff0c;服务器需要识别多次请求…

upload-Labs靶场“11-15”关通关教程

君衍. 一、第十一关 %00截断GET上传1、源码分析2、%00截断GET上传 二、第十二关 %00截断POST上传1、源码分析2、%00截断POST上传 三、第十三关 文件头检测绕过1、源码分析2、文件头检测绕过 四、第十四关 图片检测绕过上传1、源码分析2、图片马绕过上传 五、第十五关 图片检测绕…

腾讯云和阿里云哪个好?云服务器价格表对比

2024年阿里云服务器和腾讯云服务器价格战已经打响&#xff0c;阿里云服务器优惠61元一年起&#xff0c;腾讯云服务器62元一年&#xff0c;2核2G3M、2核4G、4核8G、8核16G、16核32G、16核64G等配置价格对比&#xff0c;阿腾云atengyun.com整理阿里云和腾讯云服务器详细配置价格表…

C# LINQ运算符

LINQ运算符 1. 概述1.1 集合->集合1.1.1 筛选运算符1.1.2 映射运算符1.1.3 连接运算符1.1.4 排序运算符1.1.5 分组运算符1.1.6 集合运算符1.1.7 转换方法:Import1.1.8 转换方法:Export 1.2 集合->单个元素或标量值1.2.1 元素运算符1.2.2 聚合方法1.2.3 数量词 1.3 空->…

1910_野火FreeRTOS教程阅读笔记_prvStartFirstTask函数

1910_野火FreeRTOS教程阅读笔记_prvStartFirstTask函数 全部学习汇总&#xff1a; g_FreeRTOS: FreeRTOS学习笔记 这是教程中的一个函数&#xff0c;通过汇编来实现的。注释部分以及结合后面的讲解部分&#xff0c;可能还是有一点点细节的地方让初学者疑惑。我结合我自己的理解…

龙格-库塔法

概要 微分方程&#xff1a;含参数、未知函数、未知函数的导数&#xff08;或者微分&#xff09;的方程数值求解&#xff1a;用若干离散点计算 近似值 来代替准确值分类&#xff1a;单步法、多步法&#xff1b;隐式法、显示法欧拉法 (欧拉折线法)&#xff0c;也是一阶龙格-库塔…

【数据结构】图解二叉搜索树的新增、搜索、删除

一、概念 二叉搜索树&#xff08;Binary Search Tree&#xff0c;简称BST&#xff09;也称为二叉查找树或二叉排序树&#xff0c;是一种具有特殊性质的二叉树数据结构。 定义和性质&#xff1a; 二叉搜索树中的每个节点包含一个键值&#xff0c;习惯上我们说左子树上所有节点…

乔琼:高性能会议传声器的产品优化设计| 演讲嘉宾公布

一、智能家居与会议系统 智能家居与会议系统分论坛将于3月28日同期举办&#xff01; 智能会议系统它通过先进的技术手段&#xff0c;提高了会议效率&#xff0c;降低了沟通成本&#xff0c;提升了参会者的会议体验。对于现代企业、政府机构和学术界是不可或缺的。在这里&#x…

部署运维 防火墙,进程 常用命令

防火墙: 1. 查看是否安装了firewalld sudo systemctl status firewalld 查看防火墙状态或者sudo systemctl is-active firewalld 查看防火墙是否是开启状态 2. 开放6379port sudo firewall-cmd --add-port6379/tcp --permanent 刷新防火墙 sudo firewall-cmd --reload 3…

MinIO Client(mc)基本使用

一、Linux安装 1、下载最近的mc 命令&#xff0c;并保存到当前用户的bin目录下&#xff0c;这样可以直接执行&#xff0c;不用修改path curl -sL https://dl.minio.org.cn/client/mc/release/linux-amd64/mc -o /usr/bin/mc chmod x /usr/bin/mc二、配置使用 1、查看mc已经…

【洛谷 P8748】[蓝桥杯 2021 省 B] 时间显示 题解(数学+模运算+输入输出)

[蓝桥杯 2021 省 B] 时间显示 题目描述 小蓝要和朋友合作开发一个时间显示的网站。在服务器上&#xff0c;朋友已经获取了当前的时间&#xff0c;用一个整数表示&#xff0c;值为从 1970 年 1 月 1 日 00:00:00 到当前时刻经过的毫秒数。 现在&#xff0c;小蓝要在客户端显示…

MATLAB KL变换

1. 原理 KL变换步骤&#xff1a; 1.求样本X的协方差矩阵R 2.求 R的特征值λ。选取前d个较大的特征值。 3.计算d个特征值对应的特征向量&#xff0c;归一化后构成变换矩阵U。 4.对{X}中每一个X进行K-L变换&#xff0c;得到变换后向量YU’ * X&#xff0c;d维向量Y就是…

阿里云Linux系统MySQL8忘记密码修改密码

相关版本 操作系统&#xff1a;Alibaba Cloud Linux 3.2104 LTS 64位MySQL&#xff1a;mysql Ver 8.0.34 for Linux on x86_64 (Source distribution) MySQL版本可通过下方命令查询 mysql --version一、修改my.cnf文件 文件位置&#xff1a;etc/my.cnf进入远程连接后可以打…

解决vue项目本地开发完成后部署到服务器后报404的问题

一、如何部署 前后端分离开发模式下&#xff0c;前后端是独立布署的&#xff0c;前端只需要将最后的构建物上传至目标服务器的web容器指定的静态目录下即可 我们知道vue项目在构建后&#xff0c;是生成一系列的静态文件 常规布署我们只需要将这个目录上传至目标服务器即可 /…

163邮箱SMTP设置需要怎么配置?如何开启?

163邮箱SMTP设置教程&#xff1f;163邮箱开通SMTP发信功能方法&#xff1f; 当我们需要使用第三方工具或软件来发送邮件时&#xff0c;SMTP设置就显得尤为重要。特别是对于使用163邮箱的用户来说&#xff0c;掌握163邮箱SMTP设置的方法是非常必要的。下面&#xff0c;AokSend就…

javaweb学习(day06-servlet)

一、基本介绍 1 官方文档 地址: https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.htmlServlet 和 Tomcat 的关系: 一句话, Tomcat 支持 Servlet【假如单独使用Servlet就失去了意义】 2 为什么会出现 Servlet 提出需求: 请用你现有的html css javascript&#…

JavaSE(上)-Day3

JavaSE&#xff08;上&#xff09;-Day3 IDEA&#xff08;目前业内最好用的开发软件&#xff09;初始使用IEDA的基础设置 本篇主要介绍内容如下&#xff1a; IDEA的基本使用IDEA的基础设置 IDEA&#xff08;目前业内最好用的开发软件&#xff09; IDEA是用于Java语言开发的集…

springboot之mybaitsPlus

mybaitsPlus是国内开发的&#xff0c;并不是springboot的项目&#xff0c;只是学习的时候直接就是适配的springboot。 MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不…