Java 8 Optional用法【总结记录】

news2024/11/14 17:49:26

一、前言

这里引用书中描述来介绍Optional类:

Optional是为核心类库设计的一个数据类型,用来替换null值。人们对原有的null值有很多抱怨,甚至连发明这一概念的Tony Hoare也是如此,他曾说这是自己的一个“价值连城的错误”。作为一名有影响力的科学家就是这样:虽然连一毛钱也见不到,却也可以犯一个“价值连城的错误”。

-- 摘自 Java 8函数编程

人们常常使用null值表示值不存在,Optional对象能更好地表达这个概念。使用null代表值不存在的最大问题在于NullPointerException。一旦引用一个存储null值的变量,程序会立即崩溃。使用Optional对象有两个目的:首先,Optional对象鼓励程序员适时检查变量是否为空,以避免代码缺陷;其次,它将一个类的API中可能为空的值文档化,这比阅读实现代码要简单很多。

-- 摘自 Java 8函数编程

基于上述问题,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。

java.util.Optional是Java 8引入的一个容器类,目的是解决NullPointerException的问题,它可以保存<T>的值,代表这个值存在,或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。

本质上,Optional是一个包装类,其中包含对其它对象的引用。这种情况下,对象只是指向内存位置的指针,并且也可以指向任何内容。

缺点:会造成代码过于冗长,最主要是会引入额外的对象开销,所以适当使用即可。

二、Optional特性

public final class Optional<T> {
    //Null指针的封装
    private static final java.util.Optional<?> EMPTY = new java.util.Optional<>();
    //内部包含的值对象
    private final T value;
    private Optional() ;
    //返回EMPTY对象
    public static<T> java.util.Optional<T> empty() ;
    //构造函数,但是value为null,会报NPE
    private Optional(T value);
    //静态工厂方法,但是value为null,会报NPE
    public static <T> java.util.Optional<T> of(T value);
    //静态工厂方法,value可以为null
    public static <T> java.util.Optional<T> ofNullable(T value) ;
    //获取value,但是value为null,会报NoSuchElementException
    public T get() ;
    //返回value是否为null
    public boolean isPresent();
    //如果value不为null,则执行consumer式的函数,为null不做事
    public void ifPresent(Consumer<? super T> consumer) ;
     //过滤,如果value不为null,则根据条件过滤,为null不做事
    public java.util.Optional<T> filter(Predicate<? super T> predicate) ;
     //转换,在其外面封装Optional,如果value不为null,则map转换,为null不做事
    public<U> java.util.Optional<U> map(Function<? super T, ? extends U> mapper);
     //转换,如果value不为null,则map转换,为null不做事
    public<U> java.util.Optional<U> flatMap(Function<? super T, java.util.Optional<U>> mapper) ;
    //value为null时,默认提供other值
    public T orElse(T other);
      //value为null时,默认提供other值
    public T orElseGet(Supplier<? extends T> other);
      //value为null时,默认提供other值
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) ;
}

Optional类提供了大约10种方法,我们可以使用它们来创建和使用Optional类,下面将介绍如何使用它们。

三、Optional用法

3.1 empty

创建一个值为空的Optional对象。

Optional<String> empty = Optional.empty();

如果对象为空,请避免使用==Optional.empty()返回的实例比较,因为不能保证它是一个单例,应该使用isPresent方法。

3.2 of

创建一个特定的非空值Optional对象。

String name = "java";
Optional<String> opt = Optional.of(name);

静态方法需要一个非null参数;否则将引发NullPointerException异常。如果我们不知道参数是否为null,可以使用ofNullable方法。

在这里插入图片描述

3.3、ofNullable

创建一个(兼容null值)Optional对象。

Optional<String> optional = Optional.ofNullable(null);

如果我们传入一个空引用,它不会抛出NullPointerException异常,而是返回一个空的Optional对象。

3.4 isPresent

如果Optional对象所包含的值为null,则返回false,反之返回true。通常在对对象执行任何其他操作之前,先在Optional上调用此方法。

Optional<String> optional = Optional.of("value");
if (optional1.isPresent()){
	//Do something, normally a get
}

3.5 isEmpty

如果Optional对象所包含的值为null,则返回true,反之返回false(这与isPresent相反,并且仅在Java 11及更高版本中可用)。

Optional<String> optional = Optional.of("value");
if (optional1.isEmpty()){
  //Do something
}

3.6 ifPresent

如果Optional对象存在值,则使用该值调用指定的使用者;否则什么都不做。

Optional<String> optional = Optional.of("value");
optional1.ifPresent(s -> System.out.println(s.length()));

补充:ifPresent和isPresent方法有相似之处,但它们的用途略有不同:

  1. ifPresent:如果Optional对象中存在非空值,则执行给定的消费者操作(Consumer)。这个方法不返回任何值,主要用于执行某个操作而不关心操作的结果。
  2. isPresent:判断Optional对象中是否存在非空值,并返回一个布尔值。这个方法通常用于在存在非空值时执行一段代码,在不存在非空值时执行另一段代码。

3.7 get

用于获取Optional中的值,如果此Optional中存在值则返回该值,否则抛出NoSuchElementException(这就可以使用orElse方法来紧急救援)。

Optional<String> optional1 = Optional.of("value");
if (optional1.isPresent()){
  String value = optional1.get();
}

在这里插入图片描述

3.8 orElse和orElseGet

orElse和orElseGet是两个常用的方法,用于当Optional中的值为空时,为Optional提供默认值。

示例:假设下面getDefaultValue方法返回值为default value,那么当Optional对象值为null时,通过orElse和orElseGet方法补充默认值后,最后都会输出default value。

Optional<String> optional = Optional.ofNullable(null);

// 使用 orElse 方法
String result1 = optional.orElse(getDefaultValue());
System.out.println(result1); // 输出:default value

// 使用 orElseGet 方法
String result2 = optional.orElseGet(this::getDefaultValue);
System.out.println(result2); // 输出:default value

1、相同点:

在上面的代码中,orElse和orElseGet方法的行为是相同的。它们都只有在Optional对象中没有值时才会调用getDefaultValue方法来获取默认值。

2、不同点:

参数不同:orElse方法接受一个对象作为参数,orElseGet方法接受一个Supplier接口类型的对象作为参数。

性能不同:当你使用orElse方法时,作为参数的默认值对象会在调用该方法时立即被创建或计算。这意味着无论Optional对象中是否有值,默认值对象都会被创建或计算。

相反,使用orElseGet方法时,getDefaultValue方法只有在Optional对象中没有值时才会被调用。在下面例子中,因为Optional对象中已经有了一个非空的值,getDefaultValue方法并不会被调用。

假设上述getDefaultValue方法它执行了一个非常耗时的操作来生成一个默认值,而Optional中已经存在非空的值,使用orElse方法时getDefaultValue方法仍然会被调用,尽管它的结果并不会被使用。这种情况下,使用orElse方法可能会浪费资源。

总的来说,orElseGet方法在需要懒惰地计算默认值或者提高代码可读性时更为适用。

3.9 orElseThrow

除了上述基本用法之外,Optional类还提供了一种强大的orElseThrow方法。这个方法接受一个Supplier接口类型的对象作为参数,该对象提供了一个异常实例,当Optional对象值为空时,该方法会抛出制定的异常(可以为自定义异常)。

Optional<String> optional = Optional.ofNullable(null);

try {
    String result = optional.orElseThrow(() -> new Exception("No value present"));
    System.out.println(result);
} catch (Exception e) {
    System.out.println(e.getMessage()); // 输出:No value present
}

在上面的代码中,orElseThrow方法被用来在Optional对象中没有值时抛出一个Exception。如果Optional对象中有值,orElseThrow方法会返回该值;否则,它会抛出由Supplier提供的异常。

orElseThrow方法的签名如下:

public T orElseThrow(Supplier<? extends X> exceptionSupplier)

其中,T是Optional对象中可能存在的值的类型,X是要抛出的异常的类型。

需要注意的是,orElseThrow方法并不是在所有情况下都适用。它应该只在遇到无法恢复的错误时使用,例如在程序逻辑上不允许出现空值的情况下。如果你只是想提供一个默认值,应该使用orElse或orElseGet方法。

此外,orElseThrow方法在Java 10中被简化了,可以直接传入一个异常类,而不需要使用Supplier:

Optional<String> optional = Optional.ofNullable(null);

try {
    String result = optional.orElseThrow(Exception.class);
    System.out.println(result);
} catch (Exception e) {
    System.out.println(e.getMessage()); // 输出:No value present
}

这个简化版的orElseThrow方法会在Optional对象中没有值时抛出一个NoSuchElementException异常,异常消息是"No value present"。

总的来说,orElseThrow方法可以帮助你在处理可能为空的值时更加明确地表达你的意图,并在必要时抛出一个异常来处理错误情况。

四、最后

Optional 对象不仅可以用于新的Java 8 API,也可用于具体领域类中,和普通的类别无二致。当试图避免空值相关的缺陷,如未捕获的异常时,可以考虑一下是否可使用Optional对象。

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

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

相关文章

cad导出图片格式怎么导出?5个软件帮助你快速转换文件格式

cad导出图片格式怎么导出&#xff1f;5个软件帮助你快速转换文件格式 将CAD文件导出为图片格式可以帮助你更方便地展示、分享或打印设计图纸。CAD&#xff08;Computer-Aided Design&#xff09;文件通常以DWG或DXF格式保存&#xff0c;而要将它们转换为常见的图片格式&#x…

NodeJS “次元高校”社团管理系统 ---附源码94897

摘要 计算机科学技术的飞速发展也更好地促进了高校信息化建设。为了适应新形势下更好地培养人才&#xff0c;高校在发展的过程中开始推进信息系统的建设。随着我国教育模式的不断改革和发展&#xff0c;越来越多的高校正在开展校园信息工程建设&#xff0c;以更好地提高高校的各…

C / C++内存管理

内存分布 1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等&#xff0c;栈是向下增长的。 2. 内存映射段是高效的I/O映射方式&#xff0c;用于装载一个共享的动态内存库。用户可使用系统接口创建共享共 享内存&#xff0c;做进程间通信&#xff0c;子进程堆区的开辟。 3. …

文心快码帮你解大厂面试题:TCP关闭连接的过程,为什么要4次挥手,为什么最大等待时间是2*MSL?

&#x1f50d;【大厂面试真题】系列&#xff0c;带你攻克大厂面试真题&#xff0c;秒变offer收割机&#xff01; ❓今日问题&#xff1a;在8g内存的机器&#xff0c;能否启动一个7G堆大小的java进程&#xff1f; ❤️一起看看文心快码Baidu Comate给出的答案吧&#xff01;如…

Oracle RAC 修改系统时区避坑指南(深挖篇)

大家好&#xff0c;这里是 Lucifer三思而后行&#xff0c;专注于提升数据库运维效率。 目录 前言环境安装问题重现时区检查修改时区问题分析问题解决 深究根源问题一问题二问题三 写在最后往期精彩文章推荐 前言 昨天遇到一个问题&#xff0c;Oracle RAC 安装完之后&#xff0…

bitsandbytes使用错误:CUDA Setup failed despite GPU being available

参考:https://huggingface.co/docs/bitsandbytes/main/en/installation 报错信息 ======================

【JavaEE精炼宝库】网络原理基础——网络层 | IP协议

文章目录 一、IP 协议的格式二、IP 地址的数量限制三、私有 IP 地址和公网 IP 地址3.1 私有 IP 地址和公网 IP 地址的基本知识&#xff1a;3.2 内网 IP 设备访问外网 IP 设备的过程&#xff08;NAT 机制&#xff09;&#xff1a; 四、地址管理4.1 网段划分&#xff1a;4.1.1 网…

npm、cnpm、pnpm、yarn包管理工具别傻傻分不清楚了

干啥的&#xff1a; nodejs的包管理工具。 用于自动化处理包的安装、更新、配置和管理。它们之间的主要区别在于它们各自的实现方式、性能优化、以及一些特有的功能。 怎么用&#xff1a; 1、npm 1.1、描述 Node Package Manager默认包管理器从 npm 公共仓库中安装、共享…

.net framework 4.8 开发windows系统服务

ps:旧技术了&#xff0c;有一点局限性&#xff0c;但好像网上记录并不多&#xff0c;或是很零散&#xff0c;比较坑人。故自己记录一下。 项目环境&#xff1a; win 10、.Net framework 4.8&#xff0c;Visual Studio 2019&#xff0c;oracle 12G&#xff0c;ORM是SqlSugar5.…

uniapp video标签无法播放视频

当video标签路径含有中文以及特殊字符视频就会无法播放 解决方法使用encodeURIComponent对路径进行加密处理 videoSrc data.coursewareFile? ${appConfig.apiUrl encodeURIComponent(data.coursewareFile)}: "";最后效果

GHA高质量seo文章怎么写?

撰写高质量SEO文章不仅仅是文字的堆砌&#xff0c;更是对内容的精心打磨&#xff0c;而GHA文章更是如此&#xff0c;想写出一篇GHA文章&#xff0c;首先就要保证以下几点&#xff0c;一定要原创&#xff0c;谷歌对于原创内容是极其看重的&#xff0c;哪怕是伪原创&#xff0c;在…

一种导出PPT到MP4的方法

需求 导出PPT到MP4&#xff0c;并记录每页&#xff0c;每个动作的时间线。通过 MP4时间线 就可以在页面上很方便的放映PPT的内容&#xff0c;并支持翻页点击。 代码 保存每一页的图像信息&#xff0c;用做播放器的缩略图 public void SaveThumbnail(string ppt_filepath, st…

【STL】红黑树的全面探索与红黑树的实现

ps&#xff1a;文章最后有完整的代码 1.红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路…

如何使用IDEA搭建Mybatis框架环境

文章目录 ☕前言为什么学习框架技术Mybatis框架简介 &#x1f379;一、如何配置Mybatis框架环境1.1下载需要MyBatis的jar文件1.2部署jar文件1.3创建MyBatis核心配置文件configuration.xml1.4.创建持久类(POJO)和SQL映射文件1.5.创建测试类 &#x1f9cb;二、 MyBatis框架的优缺…

前端性能优化:使用Vue3+TS+Canvas对图片进行压缩后再上传,优化带宽,减小服务器存储成本,减少流量损耗

在上传图片之前&#xff0c;对图片进行压缩。看到这里是不是有点懵&#xff0c;前端怎么压缩图片呢&#xff0c;这不应该是后端做的吗&#xff1f; 但是我在开发的时候接到了这样一个需求&#xff0c;要求对用户上传的图片进行一定的压缩&#xff0c;而且并且尽量还原图片的清…

大模型如何改变世界?李彦宏:未来至少一半人要学会“提问题“

2023年爆火的大模型&#xff0c;对我们来说意味着什么&#xff1f; 百度创始人、董事长兼CEO李彦宏认为&#xff0c;“大模型即将改变世界。” 5月26日&#xff0c;李彦宏参加了在北京举办的2023中关村论坛&#xff0c;发表了题为《大模型改变世界》的演讲。李彦宏认为&#…

2024年新算法-基于SBOA-BP混合神经网络的数据预测(Python代码实现)

在今天的数字化时代&#xff0c;机器学习和人工智能领域的不断发展为数据处理和预测提供了强大的工具。其中&#xff0c;BP神经网络&#xff08;反向传播神经网络&#xff09;作为一种经典的网络模型&#xff0c;因其能够处理复杂的非线性问题而备受关注。然而&#xff0c;传统…

吴恩达机器学习课后作业-07kmeans and pca

k-均值与PCA k-均值图片颜色聚类 PCA&#xff08;主成分分析&#xff09;对x去均值化图像降维 k-均值 K-均值是最普及的聚类算法&#xff0c;算法接受一个未标记的数据集&#xff0c;然后将数据聚类成不同的组。 K-均值是一个迭代算法&#xff0c;假设我们想要将数据聚类成n个…

python-变量声明、数据类型、标识符

一.变量 1.什么是变量 为什么需要变量呢&#xff1f; 一个程序就是一个世界&#xff0c;不论使用哪种高级程序语言编写代码&#xff0c;变量都是其程序的基本组成单位。如下图所示的sum和sub都是变量。 变量的定义&#xff1a; 变量相当于内存中一个数据存储空间的表示&#…

Spring MVC常用注解及用法

目录 1.建立连接--RequestMapping 2.请求 2.1 传递单个参数 2.2 传递多个参数 2.3 传递对象 2.4 参数重命名--RequestParam 2.5 传递数组 2.6 传递集合 2.7 传递json数据--RequestBody 2.8 获取URL中参数--PathVariable 2.9 上传文件--RequestPart 2.10 获取Cookie--…