0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

JDK8新增的Optional类的常用方法

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-09-30 15:13 次阅读

一、摘要

NullPointerException,中文名: 空指针异常 ,也简称 NPE,是软件系统中最常见的错误异常之一。

很久以前 Google Guava 项目引入了Optional作为解决空指针异常的一种方式,不赞成写过多的代码来显式检查null,以期望程序员写出整洁同时可读性更高的代码。

受 Google Guava 的影响,Optional 现在也成为了Java 8 及以上库代码的一部分。

在介绍Optional技术之前,我们不禁会发出一个疑问:为什么谷歌不赞成写过多的代码来显式检查null

下面是某个常见的参数判空代码,样例如下。

// 判断行政区是否为空
if(country != null){
    // 判断行政区的上一级,行政城市是否为空
    if(country.getCity() != null){
        // 判断行政城市的上一级,行政省是否为空
        if(country.getCity().getProvince() != null){
            // 获取对应的行政省相关的数据
            return country.getCity().getProvince().getName();
        }
    }
}

这还是最普通的三层判断,假如有很大一段业务逻辑处理的时候,你会发现代码不光看起来很臃肿,并且难以阅读,可读性很差!

如果调整为使用Optional来编写的话,可以转换成如下写法:

// 获取当前行政区最顶级的省信息名称
String result  = Optional.ofNullable(country)
                .map(Country::getCity)
                .map(City::getProvince)
                .map(Province::getName)
                .orElse("error");

采用Optional编程之后,整个代码的可读性和整洁度,是不是要干净很多!

这也是为什么推荐大家使用Optional的原因啦!

当然废话也不多说,代码直接撸起来!

二、案例实践

在 JDK8 中,Optional 共有 12 个核心方法,下面我们一起来看看他们的用法!

2.1、empty()

empty 方法返回一个不包含值的 Optional 实例,单独使用没什么意义,主要和其他方法搭配使用。

Optional optional = Optional.empty();
System.out.println(optional);
-- 输出结果
Optional.empty

2.2、of()

of 方法会返回一个 Optional 实例,如果传入的值非空,会返回包含指定值的对象;如果传入空,会立刻抛出空指针异常。

// 非空情况下,会正常返回
Optional optional = Optional.of("hello world");
System.out.println(optional);
-- 输出结果
Optional[hello world]
// 为空情况下,会抛空指针异常
Optional optional = Optional.of(null);
System.out.println(optional);
-- 输出结果
Exception in thread "main" java.lang.NullPointerException
 at java.util.Objects.requireNonNull(Objects.java:203)
 at java.util.Optional.< init >(Optional.java:96)
 at java.util.Optional.of(Optional.java:108)

2.3、ofNullable()

ofNullable 方法会返回一个 Optional 实例,如果传入的值非空,会返回包含指定值的对象;如果传入空,会返回不包含任何值的 empty 对象,也就是最开始介绍的Optional.empty()对象。

// 非空情况下,会正常返回
Optional optional = Optional.ofNullable("hello world");
System.out.println(optional);
-- 输出结果
Optional[hello world]
// 为空情况下,会返回 empty 对象
Optional optional = Optional.ofNullable(null);
System.out.println(optional);
-- 输出结果
Optional.empty

2.4、isPresent()

isPresent 方法用来判断实例是否包含值,如果包含非空值,返回 true,否则返回 false。

// 非空值,返回true
boolean rs1 =  Optional.ofNullable("hello").isPresent();
System.out.println(rs1);

// 空值,返回false
boolean rs2 =  Optional.ofNullable(null).isPresent();
System.out.println(rs2);
-- 输出结果
true
false

2.5、get()

get 方法,如果实例包含非空值,则返回当前值;否则抛出 NoSushElementException 异常。

// 非空值,返回当前值
Object rs =  Optional.ofNullable("hello world").get();
System.out.println(rs);
-- 输出结果
hello world
// 空值,会抛出 NoSushElementException 异常
Object rs =  Optional.ofNullable(null).get();
System.out.println(rs);
-- 输出结果
Exception in thread "main" java.util.NoSuchElementException: No value present
 at java.util.Optional.get(Optional.java:135)

2.6、ifPresent()

ifPresent 方法作用是当实例包含非空值时,执行传入的 Consumer,比如调用一些其他方法;如果包含的值为空,不执行任何操作。

Optional.ofNullable("hello world")
                .ifPresent( x - > {
                    System.out.println(x);
                });
-- 输出结果
hello world

2.7、filter()

filter 方法用于过滤不符合条件的值,接收一个Predicate参数,如果符合条件,会返回当前的Optional实例,否则返回 empty 实例。

Optional.ofNullable("hello world")
                .filter(x - > x.contains("hello"))
                .ifPresent(x - > {
                    System.out.println(x);
                });
-- 输出结果
hello world

2.8、map()

map 方法是链式调用避免空指针的核心方法,当实例包含值时,对值执行传入的Function函数接口方法,并返回一个代表结果值新的Optional实例,也就是将返回的结果再次包装成Optional对象。

Optional.ofNullable("hello+world")
                .map(t - > {
                    if(t.contains("+")){
                        return t.replace("+", " ");
                    }
                    return t;
                }).ifPresent(t - > {
                    System.out.println(t);
                });
-- 输出结果
hello world

2.9、flatMap()

flatMap 方法与 map 方法类似,唯一不同的地方在于: 需要手动将返回的值,包装成Optional实例,并且参数值不允许为空

Optional.ofNullable("hello+world")
                .flatMap(t - > {
                    if(t.contains("+")){
                        t =  t.replace("+", " ");
                    }
                    // 不同之处
                    return Optional.of(t);
                }).ifPresent(t - > {
                    System.out.println(t);
                });
-- 输出结果
hello world

2.10、orElse()

orElse 方法作用是如果实例包含非空值,那么返回当前值;否则返回指定的默认值。

Object rs =  Optional.ofNullable(null).orElse("null");
System.out.println(rs);
-- 输出结果
null

2.11、orElseGet()

orElseGet 方法作用是如果实例包含非空值,返回这个值;否则,它会执行作为参数传入的Supplier函数式接口方法,并返回其执行结果。

Object result = Optional.ofNullable(null)
                .orElseGet(() - > {
                    return "error";
                });
System.out.println(result);
-- 输出结果
error

2.12、orElseThrow()

orElseThrow 方法作用是如果实例包含非空值,返回这个值;否则,它会执行作为参数传入的异常类。

Optional.ofNullable(null)
                .orElseThrow(() - > new RuntimeException("参数为空"));
-- 输出结果
Exception in thread "main" java.lang.RuntimeException: 参数为空
 at com.x.x.x.x.OptionalTest.lambda$main$10(OptionalTest3.java:144)
 at java.util.Optional.orElseThrow(Optional.java:290)

三、小结

以上就是 JDK8 新增的Optional类的常用方法总结,其中ofNullablemaporElse方法搭配使用的最多。

另外orElseorElseGetorElseThrow区别如下:

  • orElse:如果实例包含空值,返回传入指定的值
  • orElseGet:如果实例包含空值,返回传入的方法中返回值
  • orElseThrow:如果实例包含空值,返回指定的异常类型

在实际使用的时候,还得结合具体的场景进行合理选择,有时候并不是全部采用Optional来解决NPE异常代码才更加优雅,比如当前对象比较简单,就是一个简单判断,通过obj != null足以解决问题。

因此在保证业务功能的正确和稳定性的基础之上,适当的选择相关的工具来优化代码的整洁度和可读性,更能发挥出锦上添花的效果!

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 程序
    +关注

    关注

    116

    文章

    3754

    浏览量

    80722
  • 代码
    +关注

    关注

    30

    文章

    4714

    浏览量

    68196
  • 软件系统
    +关注

    关注

    0

    文章

    61

    浏览量

    9471
  • jdk8
    +关注

    关注

    0

    文章

    4

    浏览量

    1916
收藏 人收藏

    评论

    相关推荐

    JDK动态代理的原理

    在Java中,动态代理是一种机制,允许在运行时动态地创建代理对象来代替某个实际对象,从而在其前后执行额外的逻辑。 为什么JDK动态代理只能代理接口实现,原因是JDK动态代理是基于接口实现的。 当你
    的头像 发表于 09-30 10:51 532次阅读

    树莓派安装JDK

    /jdk8-downloads-2133151.html最新版本jdk8下载的文件jdk-7u60-linux-arm-vfp-hflt.tar.gz 2、在home下面创建tool文件夹,解压
    发表于 03-05 15:12

    毕昇JDK 8 Dynamic CDS 特性介绍

    内存中的到 JSA 文件。毕昇JDK 8 中实现的 Dynamic CDS 特性相比之前的 AppCDS ,增加了 Custom ClassLoader 的支持,扩展了共享的支持
    发表于 12-23 16:19

    JDK8 Optional新特性

    Optional不是对null关键字的一种替代,而是对于null判定提供了一种更加优雅的实现。 NullPointException可以说是所有java程序员都遇到过的一个异常,虽然java从
    发表于 11-28 14:33 1759次阅读

    Java数组的常用方法_Java:数组工具Arrays常用方法的用法及代码

    本文主要详细介绍了Java数组的常用方法以及数组工具Arrays常用方法的用法及代码。
    发表于 01-29 10:25 2903次阅读

    简述那些JDK中坑你没商量的方法

    前言 JDK 作为我们每天必备的调用库,里面大量提供了基础供我们使用。可以说离开 JDK ,我们的 Java代码寸步难行。 JDK 带给
    的头像 发表于 06-12 17:36 1203次阅读
    简述那些<b class='flag-5'>JDK</b>中坑你没商量的<b class='flag-5'>方法</b>

    如何解决JDK8小版本升级后性能下降的问题

    编者按:在升级 JDK8U 的小版本后(从 8u74 升级到 8u202),遇到性能剧烈下降的问题(性能下降 13 倍)。该应用是一个非常简单的 Web 应用,且应用在 JDK 升级前
    的头像 发表于 07-26 14:44 4017次阅读
    如何解决<b class='flag-5'>JDK8</b>小版本升级后性能下降的问题

    毕昇JDK8JDK11首次同时发布两个版本

    2021 年 9 月 30 日,毕昇 JDK update Q3 版本正式发布,本次发布将包含 X86_64 版本。此前,毕昇 JDK 只发布 Aarch64 版本,这可能会对运维产生一定
    的头像 发表于 10-28 10:53 3220次阅读
    毕昇<b class='flag-5'>JDK8</b>和<b class='flag-5'>JDK</b>11首次同时发布两个版本

    JAVA8提供了Optional来优化这种写法

    这种写法是比较丑陋的,为了避免上述丑陋的写法,让丑陋的设计变得优雅。JAVA8提供了Optional来优化这种写法,接下来的正文部分进行详细说明
    的头像 发表于 04-24 15:18 1029次阅读

    JDK8 Stream数据流效率分析

    Stream 是Java SE 8库中新增的关键抽象,它被定义于 java.util.stream (这个包里有若干流类型:Stream 代表对象引用流,此外还有一系列特化流,如 IntStream,LongStream
    的头像 发表于 08-17 10:53 1194次阅读

    基于JDK 1.8来分析Thread的源码

    由上图我们可以看出,Thread实现了Runnable接口,而Runnable在JDK 1.8中被@FunctionalInterface注解标记为函数式接口,Runnable接口在JDK 1.8中的源代码如下所示。
    的头像 发表于 02-06 17:12 577次阅读

    Java中Arrays是什么 Arrays常用方法

    了解Arrays的概念 **A****rrays** 位于java.util包下,Arrays是一个操作数组的工具。 Arrays常用方法 Arrays.fill:
    的头像 发表于 02-17 15:11 1000次阅读
    Java中Arrays<b class='flag-5'>类</b>是什么 Arrays<b class='flag-5'>常用</b><b class='flag-5'>方法</b>

    JDK中java.lang.Arrays 的源码解析

    揭开它神秘的面纱。 java.util.Arrays JDK 提供的一个工具,用来处理数组的各种方法,而且每个方法基本上都是静态
    的头像 发表于 10-11 15:31 559次阅读
    <b class='flag-5'>JDK</b>中java.lang.Arrays <b class='flag-5'>类</b>的源码解析

    JDK11升级JDK17最全实践干货来了

    1、前言 如果你仍在使用JDK8,那你是否曾经遇到过OutOfMemoryError的问题?你是否曾经为JVM的调优问题感到困扰?本篇文章将为你介绍一种能够提供百倍性能提升的垃圾回收器,也许能够
    的头像 发表于 06-25 14:50 636次阅读
    <b class='flag-5'>JDK</b>11升级<b class='flag-5'>JDK</b>17最全实践干货来了

    JDK8升级JDK11最全实践干货来了

    呢?值得我们升级吗?而且升级过程会遇到哪些问题呢?带着这些问题,本篇文章将带来完整的JDK8升级JDK11最全实践。 2、为什么升级JDK11 1)性能提升 更好的垃圾收机制、更快的
    的头像 发表于 06-25 14:51 371次阅读
    <b class='flag-5'>JDK8</b>升级<b class='flag-5'>JDK</b>11最全实践干货来了