【Java高级语法】(十八)Optional类:解锁Java的Optional魔法:消灭那些隐匿的空指针,还程序世界一个安稳!~

news2024/9/28 9:27:06

Java高级语法详解之Optional类

  • 1️⃣ 概念
  • 2️⃣ 优势和缺点
  • 3️⃣ 使用
    • 3.1 常用操作API
    • 3.2 案例
    • 3.3 使用技巧
  • 4️⃣ 应用场景
  • 5️⃣ 实现原理
  • 🌾 总结

在这里插入图片描述

1️⃣ 概念

Optional类是Java 8引入的新特性,旨在解决空值(null)的处理问题。它的设计目的是为了提供一种更好的方式来处理可能为空的值,避免使用null导致空指针异常。

Optional是一个容器对象,可以持有某个类型的非空值或者空值。它是一个包装类,用于替代可能为空的引用变量。

下面是Optional类的几个特征:

  • Optional可以持有非空的值或空值;
  • 通过一系列方法,可以对Optional对象进行操作和转换;
  • Optional提供了一套简洁的API,方便进行空值处理。

2️⃣ 优势和缺点

优点

  • 提高代码的可读性和可维护性,明确表达值可能为空的语义;
  • 强制开发人员显式地处理空值情况,避免了空指针异常。

缺点

  • 可能引入一些额外的代码复杂性,增加代码量。

3️⃣ 使用

3.1 常用操作API

Java的Optional使用流程如下:

  1. 创建Optional对象:

    • 使用Optional.ofNullable(value)创建一个Optional对象,并将value作为包装值。value可以是null。
    • 使用Optional.of(value)创建一个Optional对象,并将value作为包装值。value不能为null,否则会抛出NullPointerException。
  2. 判断Optional对象是否包含值:

    • 使用optional.isPresent()方法判断Optional对象是否包含非空值。
      - 使用optional.isEmpty()方法判断Optional对象是否为空。
  3. 获取Optional对象的值:

    • 使用optional.get()方法获取Optional对象中的值。如果Optional对象包含值,返回该值;否则抛出NoSuchElementException异常。
  4. 使用默认值:

    • 使用optional.orElse(defaultValue)方法获取Optional对象的值。如果Optional对象包含值,则返回该值;否则返回指定的默认值。
    • 使用optional.orElseGet(supplier)方法获取Optional对象的值。如果Optional对象包含值,则返回该值;否则使用供应商函数生成一个值并返回。
  5. 条件过滤:

    • 使用optional.filter(predicate)方法根据条件过滤Optional对象。匹配的话返回当前Optional对象,否则返回空的Optional对象。
  6. 转换值类型:

    • 使用optional.map(mapper)方法将Optional对象中的值转换为mapper函数的结果,并返回新的Optional对象。
    • 使用optional.flatMap(mapper)方法类似map操作,但是返回的是mapper函数所返回的Optional对象本身。
  7. 其他常用方法:

    • 使用optional.ifPresent(consumer)方法,如果Optional对象包含值,则执行传入的操作。
    • 使用optional.orElseThrow()方法,获取Optional对象的值,如果Optional对象包含值,则返回该值;否则抛出NoSuchElementException异常。

在使用Optional时,应根据具体场景选择合适的方法进行操作。在链式调用中,可以通过一系列的Optional操作来进行连续、安全和可读性更高的调用流程,处理可能为空的值。

此外,使用Optional还需要注意谨慎使用get()方法获取Optional对象的值,最好使用更安全的方法如ifPresentorElse等进行值的处理,以避免空指针异常的发生。

Java的Optional类中全部的操作方法API汇总如下表:

方法名说明
boolean isPresent()判断Optional对象是否包含值。如果Optional对象包含非空值,返回true;否则返回false
ifPresent(Consumer<? super T> consumer)如果Optional对象包含值,则执行传入的操作
T get()如果Optional对象包含值,返回该值;否则抛出NoSuchElementException异常
T orElse(T other)获取Optional对象的值,若不存在则返回默认值other
T orElseGet(Supplier<? extends T> other)获取Optional对象的值,若不存在则使用提供的Supplier生成一个新值并返回
T orElseThrow()获取Optional对象的值,若不存在则抛出NoSuchElementException异常
Optional filter(Predicate<? super T> predicate)如果Optional对象包含值且满足条件,则返回当前Optional对象;否则返回空的Optional对象
map(Function<? super T, ? extends U> mapper)对Optional对象中的值进行映射操作,返回新的Optional对象
flatMap(Function<? super T, Optional> mapper)类似map操作,但返回的是mapper函数所返回的Optional对象本身

3.2 案例

下面是一个Java案例程序,演示了如何使用上述每个方法:

import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class OptionalExample {
    public static void main(String[] args) {
        // 定义字符串
        String value1 = "Hello, world!";
        String value2 = null;

        // 1、创建Optional对象,并将字符串作为包装值
        Optional<String> optional1 = Optional.ofNullable(value1);
        Optional<String> nullOpt = Optional.ofNullable(value2);
        
        // 2、创建Optional对象,并将字符串作为包装值。注意这种方式下,value不能为null,否则会抛出NullPointerException
        Optional<String> optional2 = Optional.of("Hello, Java!");
        //value为null,会抛出NullPointerException
        try {
            nullOpt = Optional.of(value2);
        }catch (NullPointerException e){
            System.out.println(e);
        }

        // 3、创建一个空的Optional对象
        Optional<String> optional = Optional.empty();
        System.out.println("\n" + optional);
        
        // 4、判断Optional对象是否包含非空值
        System.out.println("\nIs optional1 present? " + optional1.isPresent());
        System.out.println("Is nullOpt present? " + nullOpt.isPresent());
        
        // 5、获取Optional对象中的值,如果不存在则抛出NoSuchElementException异常
        String result1 = optional1.get();
        System.out.println("\nValue of optional1: " + result1);
        try {
            String tempResult = nullOpt.get();
            System.out.println("Value of nullOpt: " + tempResult);
        }catch (NoSuchElementException e){
            System.out.println(e);
        }

        // 6、获取Optional对象的值,若不存在则返回指定的默认值
        String result2 = optional2.orElse("Default Value");
        System.out.println("\nValue of optional2: " + result2);
        String defaultResult = nullOpt.orElse("Default Value");
        System.out.println("Value of nullOpt: " + defaultResult);

        // 7、获取Optional对象的值,若不存在则使用提供的Supplier生成一个新值
        Supplier<? extends String> other = () -> "Generated Value";
        String result3 = optional2.orElseGet(other);
        System.out.println("\nValue of optional2: " + result3);
        String generatedResult = nullOpt.orElseGet(other);
        System.out.println("Value of nullOpt: " + generatedResult);
        
        // 8、根据条件过滤Optional对象,返回满足条件的Optional对象
        Predicate<? super String> predicate = s -> s.length() > 10;
        Optional<String> filteredOptional = optional1.filter(predicate);
        System.out.println("\nFiltered optional1: " + filteredOptional);
        filteredOptional = nullOpt.filter(predicate);
        System.out.println("Filtered nullOpt: " + filteredOptional);
        
        // 9、将Optional对象中的值转换为mapper函数的结果,并返回新的Optional对象
        Optional<Integer> lengthOptional = optional1.map(String::length);
        System.out.println("\nLength of optional1: " + lengthOptional.orElse(0));
        
        // 10、类似map操作,返回的是mapper函数所返回的Optional对象本身
        Optional<String> flatMappedOptional = optional1.flatMap(s -> Optional.of(s.toUpperCase()));
        System.out.println("\nFlattened and mapped optional1: " + flatMappedOptional.orElse(""));
        
        // 11、如果Optional对象包含值,则执行传入的操作
        System.out.println();
        optional2.ifPresent(System.out::println);

        // 12、获取Optional对象的值,若不存在则抛出自定义的异常
        try {
            String result = optional.orElseThrow(() -> new Exception("Exception: Value is not present"));
            System.out.println("\nValue of optional: " + result);
        }catch (Exception e) {
            System.out.println("\n" + e.getMessage());
        }
    }
}

运行结果如下:

java.lang.NullPointerException

Optional.empty

Is optional1 present? true
Is nullOpt present? false

Value of optional1: Hello, world!
java.util.NoSuchElementException: No value present

Value of optional2: Hello, Java!
Value of nullOpt: Default Value

Value of optional2: Hello, Java!
Value of nullOpt: Generated Value

Filtered optional1: Optional[Hello, world!]
Filtered nullOpt: Optional.empty

Length of optional1: 13

Flattened and mapped optional1: HELLO, WORLD!

Hello, Java!

Exception: Value is not present

3.3 使用技巧

使用Optional时可以考虑以下几点优化技巧:

  1. 尽量不要在方法参数或返回类型中使用Optional。Optional主要用于局部变量和字段,以表明其可能为空;
  2. 尽量避免使用optional.get()方法获取Optional对象的值,可以使用ifPresentorElse等更安全的方法来处理值的情况;
  3. 谨慎使用嵌套Optional,避免过度复杂化逻辑。

4️⃣ 应用场景

常见的应用场景包括:

  • 避免null处理:Optional可以使得代码更加清晰明确,避免因为忽略处理空值而导致空指针异常;
  • 方法返回值:用于替代可能为空的返回值,以便提供更好的可读性;
  • 链式调用:通过一系列的Optional操作,可以进行连续且安全的调用链。

结合实际生产应用来说,Optional在以下业务场景可以发挥重要的作用:

  • 处理外部API调用,当返回值可能为空时使用Optional来封装;
  • 解析JSON对象时,若某些字段为可选字段,可使用Optional来处理;
  • 在数据库查询中,如果结果可能为空,可以使用Optional处理。

5️⃣ 实现原理

Optional类是一个常规的、泛型化的类,通过包装值的方式来处理可能为空的情况。它采用了一些与空对象模式相关的思想,Optional类提供了一组丰富的操作方法,以便更方便地处理可选值,避免了使用空对象时的空指针异常。

Optional类的设计灵感之一可以类比为空对象模式(Null Object Pattern)。
在空对象模式中,需要处理某个操作的对象可能为空,而使用空对象作为代替,以避免空指针异常。
对于Optional类来说,当value字段为null时,表示该Optional对象为空,它也被视作特殊的空对象。

Optional类内部有一个私有字段value,用于存储包装的值。value字段的类型是泛型T,即可以是任何类型的值。如果Optional对象包含一个非空值,则value字段存储这个值;如果Optional对象为空,则value字段为null。

🌾 总结

Optional类是Java 8引入的强大工具,用于解决空值处理问题。它可以用于包装可能为空的引用,提供一种更优雅且可读性更高的方式来表示和处理可能为空的值。使用Optional类,我们可以明确表达值是可空的,并通过一系列简单的操作方法来避免潜在的空指针异常。

尽管Optional并不适用于所有情况,但在正确的场景下,它可以大大提高代码的可读性和可维护性。然而,需要谨慎使用Optional,避免过度使用,以免引入额外的复杂性。了解Optional的基础和高级语法、Java操作API以及实现原理等方面的知识,将有助于正确地应用和优化Optional,从而编写更稳健的Java代码。

在这里插入图片描述

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

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

相关文章

ProtoBuf介绍与使用

文章目录 1、ProtoBuf概述2、下载和安装3、简单使用 1、ProtoBuf概述 Protobuf&#xff08;Protocol Buffers&#xff09;是由Google开发的一种语言无关的数据序列化格式。它旨在将结构化数据&#xff08;如结构化消息或文档&#xff09;高效地序列化为紧凑的二进制表示&#…

python GUI工具之PyQt5模块,pyCharm 配置PyQt5可视化窗口

https://doc.qt.io/qt-5/qtwidgets-module.html https://doc.qt.io/qt-5/qt.html#AlignmentFlag-enum 一、简介 PyQt是Qt框架的Python语言实现&#xff0c;由Riverbank Computing开发&#xff0c;是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合&#xff0c;每一…

【跑实验06】os包的理解?如何提取图片的名称?如何遍历一个文件夹,提取里面的图像名称?如何提取图片名称中的特定部分?代码错误地方修改;

文章目录 一、os包的理解1.1 文件和目录操作1.2 进程管理1.3 环境变量1.4 路径操作 二、如何提取图片的名称&#xff1f;三、遍历一个文件夹&#xff0c;提取里面的图像名称四、如何提取图片名称中的特定部分&#xff1f;五、代码报错修改 一、os包的理解 os 是 Python 中的一…

大厂OKR管理法:公开透明是最大特点

大厂OKR管理法&#xff1a;公开透明是最大的特点 仔细想&#xff0c;这是一件破天荒的事情 企业内部大部分的任务“公开透明” 公开透明会减少巨大的沟通成本 每个人的关键任务几乎是全部公开 估计少数的财务、人事、公关方面的不会 趣讲大白话&#xff1a;公开透明损耗少 【趣…

【UE 从零开始制作坦克】12-制作全自动机枪炮塔

效果 步骤 1. 下载模型和材质&#xff08;链接&#xff1a;https://download.csdn.net/download/ChaoChao66666/87951079&#xff09; 2. 将下载好的文件夹拖入UE工程中 首先点击“重置为默认”&#xff0c;然后勾选“合并网格体”&#xff0c;最后点击“导入所有” 导入后资源…

YOLOv5、YOLOv7独家原创改进:独家首发最新原创XIoU_NMS改进点,改进有效可以直接当做自己的原创改进点来写,提升网络模型性能、收敛速度和鲁棒性

💡该教程为属于《芒果书》📚系列,包含大量的原创首发改进方式, 所有文章都是全网首发原创改进内容🚀 💡本篇文章为YOLOv5、YOLOv7独家原创改进:独家首发最新原创XIoU_NMS改进点,改进有效可以直接当做自己的原创改进点来写,提升网络模型性能、收敛速度和鲁棒性。 �…

【Java】Java数组链表类详记

本文仅供学习参考&#xff01; 相关文章地址&#xff1a; https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html https://www.w3schools.com/java/java_arraylist.asp https://www.runoob.com/java/java-arraylist.html Java ArrayList 基础知识 ArrayList是 …

SpringSecurity-尚硅谷

前置知识 掌握Spring框架掌握SpringBoot使用掌握JavaWEB技术 文章目录 前置知识1. 简介1.1 概要1.2 历史 2.入门案例2.1 创建一个项目2.1.1 pom.xml2.1.2 controller层 2.2 运行这个项目2.32.4 SpringSecurity 基本原理2.5 UserDetailsService 接口讲解2.6 PasswordEncoder 接…

AI黑客松近期比赛清单;36氪AI淘宝店盈利复盘;GitHub Copilot官方最佳实践;AI在HR领域的应用探索 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; ⋙ 点击查看 AI Hackathon (黑客马拉松) 汇总清单 &#x1f916; 〖飞桨〗2023大模型应用创新挑战赛 百度飞桨联合上海市青年五十人创新创业研究院等…

【软件测试】推荐几款适合练手的项目

最近收到许多自学自动化测试的小伙伴私信&#xff0c;学习了理论知识后&#xff0c;却没有合适的练手项目。 测试本身是一个技术岗位&#xff0c;如果只知道理论&#xff0c;没有实战经验&#xff0c;在面试中很难说服面试官&#xff0c;比如什么场景下需要添加显示等待&#x…

CentOs7 安装jdk8详细教程

方法一&#xff1a;gz安装包安装&#xff08;推荐&#xff09; 1.下载所需版本的.tar.gz安装包 Oracle官网即可下载&#xff0c;选择好对应版本&#xff0c;可以先下到主机&#xff0c;然后上传到虚拟机的Linux上。&#xff08;注意&#xff1a;Oracle现在下载jdk需要注册登录…

OAuth2.0与单点登录的区别

本文说下OAuth2.0与单点登录的区别 文章目录 概述什么是单点登录单点登录和Oauth2.0的区别单点登录的实现本文小结 概述 SSO是Single Sign On的缩写&#xff0c;OAuth是Open Authority的缩写&#xff0c;这两者都是使用令牌的方式来代替用户密码访问应用。流程上来说他们非常相…

解决联网时自动打开浏览器转到必应msn网址的问题

现象 开机后或者断网重连之后&#xff0c;系统自动打开默认浏览器&#xff08;不管是IE还是谷歌&#xff0c;或其他的浏览器&#xff09;网址为http://go.microsoft.com/fwlink/?LinkID219472&clcid0x409接着转到http://cn.bing.com/ 或者 https://www.msn.com/ 解决方法…

Kafka系列 - kafka 副本|AR|ISR|OSR|Leader|Follower|HW|LEO

文章目录 01. kafka 副本信息02. kafka 中 ISR、AR和OSR代表什么&#xff1f;03. kafka 中 ISR的伸缩指什么&#xff1f;04. 什么情况下一个broker会从ISR中踢出去&#xff1f;05. kafka 副本和ISR扮演什么角色&#xff1f;06. kafka 副本长时间不在ISR中&#xff0c;意味着什么…

buuctf re(二)+ web CheckIn

目录 re xor helloword reverse3 web SUCTF 2019 CheckIn xor 1.查壳 64位&#xff0c;无壳 2.ida&#xff0c;f5查看伪代码 3.跟进global dq是八个字节&#xff0c;汇编数据类型参考汇编语言---基本数据类型_汇编db类型_wwb0111的博客-CSDN博客 4.因为global变量里有一…

多商户商城有哪些功能和优势?-加速度jsudo

电商时代下&#xff0c;传统企业商家急需拓展业务规模&#xff0c;向线上拓展&#xff0c;而多商户小程序造价低&#xff0c;效应高&#xff0c;自然就成为了很多企业商家拓展线上营销渠道的首要选择,那么多商户小程序商城涵盖哪些功能呢?下面小编就来详细为大家解答&#xff…

UE5《Electric Dreams》项目PCG技术解析 之 理解Assembly(以SplineExample为例)

文章目录 1. 什么是Assembly2. PCG部分2.1 Assembly变换2.2 Point变换2.2.1. SG_CopyPointsWithHierachy2.2.2 过滤及点变换2.2.3. ApplyHierachy 3. 小结 1. 什么是Assembly UE5.2的PCG出了有一段时间了&#xff0c;大家玩得都很开心。很多朋友可能和老王一样&#xff0c;使用…

Rust语言从入门到入坑——(10)文件与IO

文章目录 0、引入1、命令行1.1 命令行参数1.2 命令行输入 2、文件操作2.1 读取文件2.2 写入文件 3、总结 0、引入 Rust 语言的 I/O 操作&#xff0c;最基本的交互模式&#xff0c;主流语言都具备的功能。 1、命令行 1.1 命令行参数 命令行程序是计算机程序最基础的存在形式&…

B050-cms05-轮播图 cookie session 登录

目录 轮播图修改操作删除操作查询并展示所有轮播图 无状态的HTTP协议CookieCookie的原理Cookie的创建获取Cookie更新Cookie设置cookie的声明周期设置cookie访问路径Cookie优缺点 SessionSession原理创建SessionSession的使用sesion的生命周期Session的优缺点Cookie和Session的区…

定积分计算—牛顿-莱布尼兹公式、定积分的几何意义、利用奇偶性化简、利用Wallis公式

定积分计算 前言定积分的常规计算技巧—牛顿-莱布尼茨公式定积分的几何意义利用奇偶性简化计算![在这里插入图片描述](https://img-blog.csdnimg.cn/9acfec48362141ba9486630f7060d78d.jpg)利用周期性平移和缩小积分区间利用Wallis公式利用一个常见的积分公式定积分计算练习题 …