首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[Java8]如何正确使用Optional

[Java8]如何正确使用Optional

作者头像
KAAAsS
发布于 2022-01-14 10:09:38
发布于 2022-01-14 10:09:38
7.6K00
代码可运行
举报
文章被收录于专栏:KAAAsS's BlogKAAAsS's Blog
运行总次数:0
代码可运行

Optional是Java8提供的为了解决null安全问题的一个API。善用Optional可以使我们代码中很多繁琐、丑陋的设计变得十分优雅。这篇文章是建立在你对Optional的用法有一定了解的基础上的,如果你还不太了解Optional,可以先去看看相关教程,或者查阅Java文档

使用Optional,我们就可以把下面这样的代码进行改写。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static String getName(User u) {
    if (u == null || u.name == null)
        return "Unknown";
    return u.name;
}

不过,千万不要改写成这副样子。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static String getName(User u) {
    Optional<User> user = Optional.ofNullable(u);
    if (!user.isPresent())
        return "Unknown";
    return user.get().name;
}

这样改写非但不简洁,而且其操作还是和第一段代码一样。无非就是用isPresent方法来替代u==null。这样的改写并不是Optional正确的用法,我们再来改写一次。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static String getName(User u) {
    return Optional.ofNullable(u)
                    .map(user->user.name)
                    .orElse("Unknown");
}

这样才是正确使用Optional的姿势。那么按照这种思路,我们可以安心的进行链式调用,而不是一层层判断了。看一段代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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()到底。而其他语言比如kotlin,就提供了在语法层面的操作符加持:comp?.getResult()?.getChampion()?.getName()。所以讲道理在Java里我们怎么办!

Java用户听了都想打人

让我们看看经过Optional加持过后,这些代码会变成什么样子。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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."));
}

这就很舒服了。Optional给了我们一个真正优雅的Java风格的方法来解决null安全问题。虽然没有直接提供一个操作符写起来短,但是代码看起来依然很爽很舒服。更何况?.这样的语法好不好看还见仁见智呢。

还有很多不错的使用姿势,比如字符串为空则不打印可以这么写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
string.ifPresent(System.out::println);

Optional的魅力还不止于此,Optional还有一些神奇的用法,比如Optional可以用来检验参数的合法性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void setName(String name) throws IllegalArgumentException {
    this.name = Optional.ofNullable(name)
                        .filter(User::isNameValid)
                        .orElseThrow(()->new IllegalArgumentException("Invalid username."));
}

这样写参数合法性检测,应该足够优雅了吧。

2019-10-13 补充Optional的本质,提出若干应用建议。

不过这还没完,上面的两个例子其实还不能完全反应出Optional的设计意图。事实上,我们应该更进一步,减少Optional.ofNullable的使用。为什么呢?因为Optional是被设计成用来代替null以表示不确定性的,换句话说,只要一段代码可能产生null,那它就可以返回Optional。而我们选择用Optional代替null的原因,是Optional提供了一个把若干依赖前一步结果的处理结合在一起的途径。举个例子,在我们调用一个网站的登录接口的时候,大概会有以下的步骤:

  1. 发送HTTP请求,得到返回。
  2. (依赖:接口的返回)解析返回,如将Json文本形式的返回结果转化为对象形式。
  3. (依赖:解析的结果)判断结果是否成功。
  4. (依赖:若成功调用的结果)取得鉴权令牌。
  5. (依赖:获得的令牌)进行处理。

其中,第2-5步的每一个步骤都依赖于前一个步骤,而前一个步骤传递过来的数据都具不确定性(有可能是null)。所以,我们可以把它们接受的数据都设计成Optional。第1-4步每一个步骤的结果也具备不确定性,所以我们也把它们的结果设计成Optional。最后到了第5步,我们终于要对一切的结果进行处理了:如果成功获得令牌就存储,失败就提示用户。所以这一步,我们采用如orElse之类的方法来消除不确定性。于是我们最后的设计就可以是:

  1. 结果String(可能是null) == 包装 ==> Optional<String>
  2. Optional<String> == 解析 ==> Optional<Json对象>
  3. Optional<Json对象> == Filter判断成功 ==> Optional<Json对象>
  4. Optional<Json对象> == 取鉴权令牌 ==> Optional<AuthToken>
  5. Optional<AuthToken>进行处理,消除Optional

Optional就像一个处理不确定性的管道,我们在一头丢进一个可能是null的东西(接口返回结果),经过层层处理,最后消除不确定性。Optional在过程中保留了不确定性,从而把对null的处理移到了若干次操作的最后,以减少出现NPE错误的可能。于是,Optional应用的建议也呼之欲出了:

  1. 适用于层级处理(依赖上一步操作)的场合。
  2. 产生对象的方法若可能返回null,可以用Optional包装。
  3. 尽可能延后处理null的时机,在过程中使用Optional保留不确定性。
  4. 尽量避免使用Optional作为字段类型。

最后说句题外话,这种依赖上一步的操作也叫Continuation。而Optional的这种接受并组合多个Continuation的设计风格就是Continuation-passing style(CPS)。

参考资料

使用 Java8 Optional 的正确姿势 – 隔叶黄莺 Unmi Blog (https://unmi.cc/proper-ways-of-using-java8-optional/)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017/07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java8新特性探索之Optional类
身为一名Java程序员,大家可能都有这样的经历:调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法。我们首先要判断这个返回值是否为null,只有在非空的前提下才能将其作为其他方法的参数。之前,Google Guava项目曾提出用Optional类来包装对象从而解决NullPointerException。受此影响,JDK8的类中也引入了Optional类,在新版的SpringData Jpa和Spring Redis Data中都已实现了对该方法的支持。Optional是可以包含或不包含非null值的容器对象,如果存在值,则isPresent()将返回true,而get()将返回该值。
用户1289394
2020/12/08
5840
JAVA8实战 - Optional工具类
没错,这又是一个新的专栏,JAVA8可以说是JAVA划时代的一个版本,几乎是让JAVA焕发了第三春(第二春在JDK5),当然里面的新特性也是十分重要的,虽然Java现在都已经到了10几的版本,但是国内多数使用的版本还是JAVA8,所以这个系列将会围绕Java8的新特性和相关工具做一些总结。希望对大家日常学习和工作中有所帮助。
阿东
2021/08/16
1.9K0
java8 新特性 -Optional的常见用法
用户7630333
2023/12/07
7460
Java8新特性:Optional类的正确使用姿势
空指针异常是我们在实际开发中经常会遇到的问题,为了防止程序因为异常而中断,通常要在代码中添加大量的非空验证,例如一个释放 JDBC 相关资源的代码,如下所示。
南风
2019/08/01
1K0
Java8新特性:Optional类的正确使用姿势
Java8之熟透Optional
在写程序的时候一般都遇到过 NullPointerException,所以经常会对程序进行非空的判断:
用户1195962
2019/09/29
5930
Java8 Optional 的正确使用方式
1.当我们还在以如下几种方式使用 Optional 时, 就得开始检视自己了 调用 isPresent() 方法时 调用 get() 方法时 Optional 类型作为类/实例属性时 Optional 类型作为方法参数时 isPresent() 与 obj != null 无任何区别, 我们的生活依然在步步惊心. 而没有 isPresent() 作铺垫的 get() 调用在 IntelliJ IDEA 中会收到告警。调用 Optional.get() 前不事先用 isPresent() 检查值是否可用. 假
神秘的寇先森
2018/05/30
1.2K0
【Java8新特性】不了解Optional类,简历上别说你懂Java8!!
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:
冰河
2020/10/29
6560
【Java8新特性】不了解Optional类,简历上别说你懂Java8!!
Java8中使用Optional处理null对象
  Optional 是一个容器对象,可以存储对象、字符串等值,当然也可以存储 null 值。Optional 提供很多有用的方法,能帮助我们将 Java 中的对象等一些值存入其中,这样我们就不用显式进行空值检测,使我们能够用少量的代码完成复杂的流程。
Kevin_Zhang
2021/06/22
2.2K0
Java8中使用Optional处理null对象
JAVA8之妙用Optional解决判断Null为空的问题
在文章的开头,先说下NPE问题,NPE问题就是,我们在开发中经常碰到的NullPointerException.假设我们有两个类,他们的UML类图如下图所示
Java编程指南
2019/08/02
8K0
JAVA8之妙用Optional解决判断Null为空的问题
Java8 中的真的 Optional 很强大,你用对了吗?
从 Java 8 引入的一个很有趣的特性是 Optional 类。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) —— 每个 Java 程序员都非常了解的异常。本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。
Java小咖秀
2021/06/08
8650
Java8 中的真的 Optional 很强大,你用对了吗?
使用 Java 8 Optional 的正确姿势
我们知道 Java 8 增加了一些很有用的 API, 其中一个就是 Optional. 如果对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPointException 的问题, 于是代码就开始这么写了
哲洛不闹
2018/09/18
2.3K0
使用 Java 8 Optional 的正确姿势
Java8新特性之Optional类
我们从一个简单的用例开始。在 Java 8 之前,任何访问对象方法或属性的调用都可能导致 NullPointerException:
Remember_Ray
2020/08/03
5800
Java 中的 Optional
从 Java 8 引入的一个很有趣的特性是 Optional 类。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) —— 每个 Java 程序员都非常了解的异常。
BUG弄潮儿
2020/11/11
5400
聊一聊Java8 Optional,让你的代码更加优雅
Java8提供了Optional接口,Optional接口能够让我们的代码变得更加的优雅,可读性更高,同时能够很好的避免空指针,因为空指针是一个很让人头疼的问题,特别对于调用第三方接口,如果不知道对象的规约的时候,我们在取值的时候无法知道哪些些值能为空,哪些不能为空,所以容易出现空指针,如果我们谨慎一点,可能会对每一个值进行判空处理,但是将会充斥着大量的if语句,甚是不雅观。
小四的技术之旅
2022/07/26
4350
Java基础之Optional类(JDK1.8新特性)
Optional是一个容器,它可以保存类型T的值,或者仅仅保存null,Optional类主要是用来避免空指针异常(NPE),其提供的一系列的方法配合Lambda表达式可以让代码更加清晰,语义化,以及避免了空指针异常的问题,这里要注意是避免空指针异常,而不是避免返回null。
码农飞哥
2021/08/18
5680
使用Java8中的Optional类来消除代码中的null检查
lw900925.github.io/java/java8-optional.html
JAVA葵花宝典
2020/08/28
1.8K0
JDK8系列之Optional API应该怎样用?
在前面的章节的学习中,我们学习了jdk8的新特性,lambada表达式、方法引用、函数式接口等等,接着本博客继续JDK8的一个比较重要的特性,JDK8中Optional,jdk8设计这个Optional的目的就是为了避免开发中很常见的NullPointerException
SmileNicky
2021/07/23
4040
Java8 Optional
Optional是一个没有子类的工具类,是一个可以为null的容器对象,它的主要作用就是用来避免null的检查,防止出现NPE。Optional是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。Optional 类的引入很好的解决空指针异常。
HLee
2020/12/21
1K0
Java8 Optional
Java8 Optional类初体验
众所周知,在java语言开发中,NullPointerException是一直被大家所深恶痛绝的。然而在以前的java版本中,对空值的判断有繁琐而无趣。且十分影响代码的美观。例如下面这种情况:
呼延十
2019/07/01
9200
Java8 Optional用法和最佳实践
根据Oracle文档,Optional是一个容器对象,可以包含也可以不包含非null值。Optional在Java 8中引入,目的是解决  NullPointerExceptions的问题。本质上,Optional是一个包装器类,其中包含对其他对象的引用。在这种情况下,对象只是指向内存位置的指针,并且也可以指向任何内容。从其它角度看,Optional提供一种类型级解决方案来表示可选值而不是空引用。
一觉睡到小时候
2022/11/22
1.1K0
相关推荐
Java8新特性探索之Optional类
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档