Optional 使用方法详解

news2024/10/6 20:29:48

Optional的作用是什么?他都有哪些方法?阿里规范点名说尽量用Optional来避免空指针,那么什么场景用Optional?本篇文章围绕这三点来进行讲解。
在这里插入图片描述

一、Optional类的来源
到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。

二、Optional类是什么?
Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。

Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

三、Optional类用法
Optional类的Javadoc描述如下:这是一个可以为null的容器对象。
如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
如果值不存在则isPresent()方法会返回false,调用get()方法会NPE。

创建Optional类对象的方法:

Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):t可以为null

判断Optional容器中是否包含对象:

boolean isPresent() : 判断是否包含对象
void ifPresent(Consumer<? super T> consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。

获取Optional容器的对象:

T get(): 如果调用对象包含值,返回该值,否则抛异常
T orElse(T other) :如果有值则将其返回,否则返回指定的other对象。
T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。

过滤:

Optional<T> filter(Predicate<? super <T> predicate):如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional

映射

<U>Optional<U> map(Function<? super T,? extends U> mapper):如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper):如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象

四、代码示例

@Data
@AllArgsConstructor
@NoArgsConstructor
class Student {
    private String name;
    private Integer age;
}

1、创建Optional类

public void test1() {
	// 声明一个空Optional
	Optional<Object> empty = Optional.empty();
	
	// 依据一个非空值创建Optional
	Student student = new Student();
	Optional<Student> os1 = Optional.of(student);
	
	// 可接受null的Optional
	Student student1 = null;
	Optional<Student> os2 = Optional.ofNullable(student1);
}	

2、判断Optional容器中是否包含对象
isPresent不带参数,判断是否为空,ifPresent可以选择带一个消费函数的实例。(isPresent和ifPresent一个是 is 一个是 if 注意一下哈)

public void test1() {
    Student student = new Student();
    Optional<Student> os1 = Optional.ofNullable(student);
    boolean present = os1.isPresent();
    System.out.println(present);

    // 利用Optional的ifPresent方法做出如下:当student不为空的时候将name赋值为张三
    Optional.ofNullable(student).ifPresent(p -> p.setName("张三"));
}

3、获取Optional容器的对象

public void test1() throws Exception {
    Student student = null;
    Optional<Student> os1 = Optional.ofNullable(student);
    // 使用get一定要注意,假如student对象为空,get是会报错的
    // java.util.NoSuchElementException: No value present
    Student student1 = os1.get();

    // 当student为空的时候,返回我们新建的这个对象,有点像三目运算的感觉
    Student student2 = os1.orElse(new Student("张三", 18));

    // orElseGet就是当student为空的时候,返回通过Supplier供应商函数创建的对象
    Student student3 = os1.orElseGet(() -> new Student("张三", 18));

    // orElseThrow就是当student为空的时候,可以抛出我们指定的异常
    os1.orElseThrow(() -> new Exception());
}

4、过滤

public void test1() {
    Student student = new Student("李四", 3);
    Optional<Student> os1 = Optional.ofNullable(student);
    os1.filter(p -> p.getName().equals("张三")).ifPresent(x -> System.out.println("OK"));
}

5、映射
map代码示例:

public void test1() {
     Student student = new Student("李四", 3);
     Optional<Student> os1 = Optional.ofNullable(student);
     // 如果student对象不为空,就加一岁
     Optional<Student> emp = os1.map(e ->
     {
         e.setAge(e.getAge() + 1);
         return e;
     });
 }

这块的map说实话对lambda不是很熟练的 理解起来是很绕脑子的。

这里的map实际上就是用的Function函数,Function函数是有两个参数的,第一个是入参数据类型,第二个是返回数据类型。Function函数作用就是传入一个对象,然后返回一个对象,返回的对象类型可以自己设置。

T 就是代表实例的泛型数据类型,就是谁调用的 入参 必须跟调用者泛型的数据类型一样。
U 就是自己说了算,调用完map之后返回什么数据类型,那么U就设置什么
在这里插入图片描述
flatMap代码示例: flatMap跟map是一样的只不过他返回的是optional对象。

public static Optional<Integer> stringToInt(String s) {
     try {
         return Optional.of(Integer.parseInt(s));
     } catch (NumberFormatException e) {
         e.printStackTrace();
         return Optional.empty();
     }
 }

Optional.ofNullable(props.getProperty(name))
        .flatMap(OptionalUtils::stringToInt)
        .filter(i -> i>0)
        .orElse(0);

五、什么场景用Optional?
以前一直不懂Optional有啥用,感觉太无语了,Java8还把它当做一个噱头来宣传,最近终于发现它的用处了,当然不用函数式编程的话,是没感觉的;

如下提供了几个应用场景,基本上都是开发当中经常遇到的。

1、场景一

PatientInfo patientInfo = patientInfoDao.getPatientInfoById(consultOrder.getPatientId());
if (patientInfo != null) {
    consultInfoResp.setPatientHead(patientInfo.getHead());
}

// 使用Optional 和函数式编程,一行搞定,而且像说话一样
Optional.ofNullable(patientInfo).ifPresent(p -> consultInfoResp.setPatientHead(p.getHead()));

2、场景二

public void test1() throws Exception {
    Student student = new Student(null, 3);
    if (student == null || isEmpty(student.getName())) {
        throw new Exception();
    }
    String name = student.getName();
    // 业务省略...

    // 使用Optional改造
    Optional.ofNullable(student).filter(s -> !isEmpty(s.getName())).orElseThrow(() -> new Exception());
}

public static boolean isEmpty(CharSequence str) {
    return str == null || str.length() == 0;
}

3、场景三

public static String getChampionName(Competition comp) throws IllegalArgumentException {
    if (comp != null) {
        CompResult result = comp.getResult();
        if (result != null) {
            User champion = result.getChampion();
            if (champion != null) {
                return champion.getName();
            }
        }
    }
    throw new IllegalArgumentException("The value of param comp isn't available.");
}

这个在开发中是很常见的一种逻辑。去判读传进来的参数时候为空,或者是从数据库中获取的对象。由于某些原因,我们不能很流程的直接这样写。

comp.getResult().getChampion().getName()

上面的写法用Optional改写:

public static String getChampionName(Competition comp) throws IllegalArgumentException {
    return Optional.ofNullable(comp)
            .map(Competition::getResult)  // 相当于c -> c.getResult(),下同
            .map(CompResult::getChampion)
            .map(User::getName)
            .orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available."));
}

4、场景四
类型之间的转换,并且当没有值的时候返回一个默认值

int timeout = Optional.ofNullable(redisProperties.getTimeout())
					  .map(x -> Long.valueOf(x.toMillis()).intValue())
					  .orElse(10000);

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

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

相关文章

Go For Web:踏入Web大门的第一步——Web 的工作方式

Web 的工作方式 了解当你访问一个网页时&#xff0c;背后是如何运作的&#xff0c;发生了一些什么&#xff1f; 其实当你输入网址&#xff08;URL&#xff09;并按下回车之后&#xff0c;你的浏览器相当于扮演了 客户端 的角色&#xff0c;首先你的浏览器会去请求 DNS 服务器进…

uniapp软键盘谈起遮住输入框和头部被顶起的问题解决

推荐&#xff1a; pages.json中配置如下可解决头部被顶起和表单被遮住的问题。 { "path": "pages/debug/protocol/tagWord", "style": { "app-plus": { "soft…

外呼系统是什么?有什么功能?AI智能系统人工系统

很多企业往往会选择通过使用外呼系统来解决封卡问题。与传统人工拨打相比&#xff0c;外呼系统一方面可以协助销售进行高效外呼&#xff0c;同时还能保障线路稳定不封号&#xff0c;与系统的接入也可以保证客户信息的跟进&#xff0c;助力销售持续性跟进。但是看到这里也不要误…

php通过各种函数判断0和空php实例

php通过各种函数判断0和空php实例 本文给大家介绍php同各种函数判断0和空的方法&#xff0c;在文章给大家补充介绍了php 语法里0不等于null为空的解决办法 补充&#xff1a;下面给大家介绍下php 语法里0不等于null为空的解决办法 今天遇到这样一个问题是这样的: php 语句里,我…

Allure2测试报告详解

目录&#xff1a; allure2安装allure2运行方式allure2报告生成allure2报告中添加用例标题allure2报告中添加用例步骤allure2报告中添加用例链接allure2报告中添加用例分类allure2报告中添加用例描述allure2报告中添加用例优先级allure2报告中添加用例支持tags标签allure2报告中…

冠达管理:A股继续缩量整理 创业板指数走势相对偏强

周三&#xff0c;A股低开后震动调整&#xff0c;三大指数均小幅跌落&#xff0c;创业板指相对偏强。到收盘&#xff0c;上证综指跌0.49%&#xff0c;报3244.49点&#xff1b;深证成指跌0.53%&#xff0c;报11039.45点&#xff1b;创业板指跌0.01%&#xff0c;报2228.73点。 资金…

用于3D MRI和CT扫描的深度学习模型总结

医学成像数据与其他我们日常图像的最大区别之一是它们很多都是3D的&#xff0c;比如在处理DICOM系列数据时尤其如此。DICOM图像由很多的2D切片组成了一个扫描或身体的特定部分。 那么如何为这类数据构建深度学习解决方案呢?本文中将介绍6种神经网络架构&#xff0c;可以使用它…

Window版 Redis6.0.6安装

一、准备工作 下载Redis6.0.6版本&#xff08;redis官网地址&#xff1a;http://www.redis.cn/download.html&#xff09; 下载MSYS2&#xff08;清华的源&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/msys2/distrib/x86_64/&#xff09; 安装板exe结尾的文件&#xf…

chapter14:springboot与安全

Spring Boot与安全视频 Spring Security, shiro等安全框架。主要功能是”认证“和”授权“&#xff0c;或者说是访问控制。 认证&#xff08;Authentication&#xff09;是建立在一个声明主体的过程&#xff08;一个主体一般指用户&#xff0c;设备或一些可以在你的应用程序中…

【ARM64 ATF 系列 3 -- ARM64 warm reset 与 cold reset】

文章目录 ARM64 Reset1.1.1 reset 运行级别1.1.2 warm reset 寄存器1.1.3 PSCI Suspend/Resume ARM64 Reset ARMv8-A支持两种复位&#xff0c;冷复位和热复位。两者主要区别是冷复位会将debug 功能模块也一同复位&#xff0c;热复位在默认情况则不会复位 debug 功 能模块。 处理…

手机便签中可以打勾的圆圈或小方块怎么弄?

在日常的生活和工作中&#xff0c;很多网友除了使用手机便签来记录灵感想法、读书笔记、各种琐事、工作事项外&#xff0c;还会用它来记录一些清单&#xff0c;例如待办事项清单、读书清单、购物清单、旅行必备物品清单等。 在按照记录的清单内容来执行的时候&#xff0c;为了…

创建好的VMware虚拟机如何连接上外网?MobaX和XShell如何连接虚拟机

配置虚拟机网卡 首先点击VMware菜单栏&#xff0c;编辑-虚拟网络编辑器-更改设置 选择VMnet8-NAT设置&#xff0c;并记住子网IP之后有用 记住网关IP 修改实际创建的虚拟机网卡 修改设置&#xff0c;vi /etc/sysconfig/network-scripts/ifcfg-ens32 修改前&#xff1a; 修…

预测地震引发的洪水

当断层陡坡像水坝一样发挥作用时&#xff0c;地表破裂地震可能会突然改变河流的路线。研究人员现已成功模拟发生在新西兰的此类事件。 当断层位移突然改变地貌时&#xff0c;地表破裂地震可能会改变河流的路线&#xff0c;例如新西兰的怀奥托阿/克拉伦斯河&#xff0c;如图所示…

SpringBoot 的自动装配特性

1. Spring Boot 的自动装配特性 Spring Boot 的自动装配&#xff08;Auto-Configuration&#xff09;是一种特性&#xff0c;它允许您在应用程序中使用默认配置来自动配置 Spring Framework 的各种功能和组件&#xff0c;从而减少了繁琐的配置工作。通过自动装配&#xff0c;您…

算法40:移动零

一、需求 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]示例 2: 输入: nums …

opencv 基础54-利用形状场景算法比较轮廓-cv2.createShapeContextDistanceExtractor()

注意&#xff1a;新版本的opencv 4 已经没有这个函数 cv2.createShapeContextDistanceExtractor() 形状场景算法是一种用于比较轮廓或形状的方法。这种算法通常用于计算两个形状之间的相似性或差异性&#xff0c;以及找到最佳的匹配方式。 下面是一种基本的比较轮廓的流程&…

B2B2C多商户电子商务网站开发--海外商城系统搭建

一、明确目标与需求 在开始搭建海外商城系统之前&#xff0c;企业需要明确自己的目标和需求。例如&#xff0c;要面向哪些国家和地区、主要销售哪些产品、需要提供哪些语言和货币支持等。这些目标和需求将有助于企业制定合理的开发计划和方案。 二、选择合适的开发平台和工具…

【安装部署】Mysql下载及其安装的详细步骤

1.下载压缩包 官网地址&#xff1a;www.mysql.com 2.环境配置 1.先解压压缩包 2.配置环境变量 添加环境变量&#xff1a;我的电脑--->属性-->高级-->环境变量-->系统变量-->path 3.在mysql安装目录下新建my.ini文件并&#xff0c;编辑my.ini文件 编辑内容如…

Linux常规操作命令

日升时奋斗&#xff0c;日落时自省 目录 1、vim 1.1、工作模式 1.2、末行模式操作相关命令 1.2.1、保存退出操作 1.2.2、查找替换 1.3、输入模式操作相关命令 1.3.1、移动相关命令 1.3.2、删除和剪切命令 1.3.3、复制操作 1.3.4、撤销 2、head 3、tail 4、ps 5、…

HTTP代理与HTTPS代理请求的方式揭秘

今天&#xff0c;我们要一起来揭秘HTTP代理与HTTPS代理请求的方式&#xff0c;帮助大家更好地理解和使用这两种代理。我们将分析它们的不同之处&#xff0c;并提供一些实际的例子和操作经验&#xff0c;让你轻松玩转网络请求&#xff01; HTTP代理请求方式&#xff1a; HTTP代…