一个大佬说,Java8的Optional是个鸡肋,我怒了!

沙海 2021年8月27日04:29:31Java评论34字数 5411阅读18分2秒阅读模式
摘要

智能摘要

智能摘要文章源自JAVA秀-https://www.javaxiu.com/42717.html

简单理解下,Optional其实就是一个壳,里面放着原先的值,至于这个值是不是null另说,反正拿到的这个壳肯定不是null。如果在a.getAddress()时拿不到值的话,你说是会继续执行map(p->p.getProvince())还是直接跳到orElseThrow~?Supplier,所以直接入栈,然后在调用other.get的时候,createYes方法才会被触发执行,这就是两者的区别之处。文章源自JAVA秀-https://www.javaxiu.com/42717.html

原文约 5811 | 图片 23 | 建议阅读 12 分钟 | 评价反馈文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!

芋道源码 文章源自JAVA秀-https://www.javaxiu.com/42717.html

以下文章来源于yes的练级攻略,作者是Yes呀文章源自JAVA秀-https://www.javaxiu.com/42717.html

文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

yes的练级攻略.文章源自JAVA秀-https://www.javaxiu.com/42717.html

用接地气的话来分享一些后端技术或写一些想写的。文章源自JAVA秀-https://www.javaxiu.com/42717.html

文章源自JAVA秀-https://www.javaxiu.com/42717.html

点击上方“芋道源码”,选择“设为星标文章源自JAVA秀-https://www.javaxiu.com/42717.html

管她前浪,还是后浪?文章源自JAVA秀-https://www.javaxiu.com/42717.html

能浪的浪,才是好浪!文章源自JAVA秀-https://www.javaxiu.com/42717.html

每天 10:33 更新文章,每天掉亿点点头发...文章源自JAVA秀-https://www.javaxiu.com/42717.html

文章源自JAVA秀-https://www.javaxiu.com/42717.html

源码精品专栏文章源自JAVA秀-https://www.javaxiu.com/42717.html

 文章源自JAVA秀-https://www.javaxiu.com/42717.html

文章源自JAVA秀-https://www.javaxiu.com/42717.html

文章源自JAVA秀-https://www.javaxiu.com/42717.html

文章源自JAVA秀-https://www.javaxiu.com/42717.html

前言

又是一个阳光明媚的下午,群里面又在讨论技术,啧啧。文章源自JAVA秀-https://www.javaxiu.com/42717.html

马哥发言道:文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

原因是他的一位同事请假了,他接手他的代码8天了,要受不了,来看下他同事 Optional 的使用:文章源自JAVA秀-https://www.javaxiu.com/42717.html

Optional<User> userOption = Optional.ofNullable(userService.getUser(...));if (!userOption.isPresent()) {....}

if 里面还有 Optional 套 Optional ,连环判断 isPresent 的。文章源自JAVA秀-https://www.javaxiu.com/42717.html

关于 Optional 老早之前我就看到很多争论,有好多怒喷 Optional 鸡肋,是个糟糕的设计,巴拉巴拉。文章源自JAVA秀-https://www.javaxiu.com/42717.html

先抛开这些不管,反正如果平日是按照以上的用法来用 Optional 的,还是直接用 if(user != null){....} 判空算了,何必包一层 Optional,再判断呢?这样使用 Optional 是不对滴,画蛇添足。文章源自JAVA秀-https://www.javaxiu.com/42717.html

推荐下自己做的 Spring Boot 的实战项目:文章源自JAVA秀-https://www.javaxiu.com/42717.html

https://github.com/YunaiV/ruoyi-vue-pro文章源自JAVA秀-https://www.javaxiu.com/42717.html

那 Optional 应该如何用呢?

Optional 的真实执行逻辑是否与你所想的一样?文章源自JAVA秀-https://www.javaxiu.com/42717.html

今天同样还是深入源码看看。文章源自JAVA秀-https://www.javaxiu.com/42717.html

我们先来看看 Optional 设计出来的意图是什么, Java 语言架构师 Brian Goetz 是这么说的:文章源自JAVA秀-https://www.javaxiu.com/42717.html

Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null for such was overwhelmingly likely to cause errors.文章源自JAVA秀-https://www.javaxiu.com/42717.html

意思就是:Optional 可以给返回结果提供了一个表示无结果的值,而不是返回 null。文章源自JAVA秀-https://www.javaxiu.com/42717.html

简单理解下,Optional 其实就是一个壳,里面放着原先的值,至于这个值是不是 null 另说,反正拿到的这个壳肯定不是 null。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

网上比较流行的说法是 Optional 可以避免空指针,我不太赞同这种说法。因为最终的目的是拿到 Optional 里面存储的值,如果这个值是 null ,不做额外的判断,直接使用还是会有空指针的问题。文章源自JAVA秀-https://www.javaxiu.com/42717.html

我认为 Optional 的好处在于可以简化平日里一系列判断 null 的操作,使得用起来的时候看着不需要判断 null,纵享丝滑,表现出来好像用 Optional 就不需要关心空指针的情况。文章源自JAVA秀-https://www.javaxiu.com/42717.html

而事实上是 Optional 在替我们负重前行,该有的判断它替我们完成了,而且用了 Optional 最后拿结果的时候还是小心的,盲目 get 一样会抛错,Brian Goetz 说 get 应该叫 getOrElseThrowNoSuchElementException。文章源自JAVA秀-https://www.javaxiu.com/42717.html

我们来看一下代码就很清楚 Optional 的好处在哪儿了。比如现在有个 yesSerivce 能 get 一个 Yes,此时需要输出 Yes 所在的省,此时的代码是这样的:文章源自JAVA秀-https://www.javaxiu.com/42717.html

Yes yes = getYes();if (yes != null) {    Address yesAddress = yes.getAddress();    if (yesAddress != null) {        Province province = yesAddress.getProvince();        System.out.println(province.getName());    }}throw new NoSuchElementException(); //如果没找到就抛错

如果用 Optional 的话,那就变成下面这样:文章源自JAVA秀-https://www.javaxiu.com/42717.html

Optional.ofNullable(getYes())        .map(a -> a.getAddress())        .map(p -> p.getProvince())        .map(n -> n.getName())        .orElseThrow(NoSuchElementException::new);

可以看到,如果用了 Optional,代码里不需要判空的操作,即使 address 、province 为空的话,也不会产生空指针错误,这就是 Optional 带来的好处!文章源自JAVA秀-https://www.javaxiu.com/42717.html

说到这,我想提个问:文章源自JAVA秀-https://www.javaxiu.com/42717.html

如果在 a.getAddress() 时拿不到值的话,你说是会继续执行map(p -> p.getProvince()) 还是直接跳到 orElseThrow? 或者反过来如果 map(n -> n.getName()) 不为空,你说 orElseThrow 这个方法会不会执行?文章源自JAVA秀-https://www.javaxiu.com/42717.html

接下来我们就来看下源码,看看 Optional 的实现机制。文章源自JAVA秀-https://www.javaxiu.com/42717.html

推荐下自己做的 Spring Cloud 的实战项目:文章源自JAVA秀-https://www.javaxiu.com/42717.html

https://github.com/YunaiV/onemall文章源自JAVA秀-https://www.javaxiu.com/42717.html

Optional 源码

Optional 的代码十分简短且简单,如果去掉注释,我估计就100来行。文章源自JAVA秀-https://www.javaxiu.com/42717.html

来看下几个关键的成员变量:文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

符合前面提到的:Optional 就是个壳,里面的 value 才是正主。并且内置了一个 EMPTY 对象,用来替换当 value 为 null 时候的壳。文章源自JAVA秀-https://www.javaxiu.com/42717.html

现在看下上面演示的 map 方法,看看它的内部实现是如何让我们不需要做非空判断的。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

可以看到很简单,没几行代码,我把方法中的两个调用实现都贴上去,这样对着看应该会更清晰:文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

先判断 value 是否为空,如果是空的话说明真正要是值是空的,此时直接返回一个 empty(),还记得上面的 empty 方法吧?直接方式事先创建的空 Optional 。文章源自JAVA秀-https://www.javaxiu.com/42717.html

如果 value 不为空,那说明值是存在的,因此调用 mapper (就是上面我们写的 a.getAddress 之类的)来操作一波这个 value,并且用 Optional.ofNullable 包了一层,这个方法内部也看到了,如果 value 是空的话,也是返回空 Optional,否则就利用 of 包裹 value 成 Optional 返回。文章源自JAVA秀-https://www.javaxiu.com/42717.html

因此,不论你 Optional 里面到底有没有值,我 map 都能处理!如果你是空,我就返回空 Optional ,如果你有值,ok 我包裹成 Optional 返回,反正不论怎样,调用 map 的返回值都会是一个 Optional,而不是 null,所以执行时不会产生空指针的情况。文章源自JAVA秀-https://www.javaxiu.com/42717.html

还记得上面的提问吗?结合 map 的源码,现在来回答下上面的问题,看注释:文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

截个 orElseThrow 的实现,就是判断下 value ,如果是 null 就抛错。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

结合源码我们知道了答案:即使 Optional.ofNullable 返回的是空 Optional ,下面的 map 逻辑还是会执行,不会因为中间得到空值而直接跳到orElseThrow执行,这和我们平日知晓的 if else 逻辑不太一样,不为空orElseThrow也一样会执行,就是判断 value!= null然后直接返回 value 的值了。文章源自JAVA秀-https://www.javaxiu.com/42717.html

好了,逻辑就是这么简单!上面之所以说是 Optional 在替我们负重前行,是因为该有的判断一个都没少,只是它替我们做了而已。文章源自JAVA秀-https://www.javaxiu.com/42717.html

关于  Optional 还有个性能问题,我们看一下:

Optional 里有 orElseGet  和 orElse 这两个看起来挺相似的方法,都是处理当值为 null 时的兜底逻辑。可能你也在一些文章上看到说用 orElseGet 不要用 orElse ,因为在 Optional 有值时候 orElse 仍然会调用方法,所以后者性能比较差。其实从上面分析我们知道不论 Optional 是否有值,orElse 和 orElseGet  都会被执行,所以是怎么回事呢?文章源自JAVA秀-https://www.javaxiu.com/42717.html

看下这个代码:文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

这样看来 orElse 确实性能会差,奇怪了,难道是 bug?文章源自JAVA秀-https://www.javaxiu.com/42717.html

我们来看下源码。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

可以看到两者的入参不同,一个就是普通参数,一个是 Supplier。我们已经得知不论Optional.ofNullable 返回的是否是空 Optional,下面的逻辑还是会执行,所以 orElse 和 orElseGet 这两个方法无论如何都会执行。文章源自JAVA秀-https://www.javaxiu.com/42717.html

因此 orElse(createYes()) 会被执行,在参数入栈之前,执行了 createYes 方法得到结果,然后入栈,而 orElseGet 的参数是 Supplier,所以直接入栈,然后在调用 other.get 的时候,createYes 方法才会被触发执行,这就是两者的区别之处。文章源自JAVA秀-https://www.javaxiu.com/42717.html

所以才会造成上面表现出的性能问题,因此不是 BUG,也不是有些文章说的 Optional 有值 orElse 也会被执行而 orElseGet 不会执行这样不准确的说法,相信现在你的心里很有数了。文章源自JAVA秀-https://www.javaxiu.com/42717.html

既然都讲到这了,把 Optional 剩下几个方法讲讲完吧,没几个了。文章源自JAVA秀-https://www.javaxiu.com/42717.html

来看个 of 和 ofNullable 的对比,看下注释应该很清晰了。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

再来看个 isPresent() 和 ifPresent(Consumer<? super T> consumer),两者名字有细微的差别,is 和 if。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

还有个 get,这个方法要小心,如果没做好判断,直接调用,当是空 Optional 时会抛错的。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

还有个 filter逻辑 和 map 的差不多,用于过滤数据,平日基本是就是先 filter 再 map,属于基操。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

还有个 flatMap ,这个和 map 逻辑一模一样,就入参有点不一样,用在返回值不是普通对象,是 Optional 包裹的对象的场景。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

这里又得提一点了,关于 POJO 里面的属性是否应该被 Optional 包裹,或者说是否应该把 get 方法包裹成 Optional 返回,类似下面这样的代码。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

在 stackoverflow 有个类似的提问。文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

Brian Goetz 给了回答,我直接翻译了:你可能永远不应该将它用于返回结果数组或结果列表的内容,而应该返回空数组或空列表。你几乎不应该将它用作某个字段或方法参数,我认为经常使用它作为 getters 的返回值肯定是过度使用。文章源自JAVA秀-https://www.javaxiu.com/42717.html

下面也有一堆不服的,说这发言更像是您自己所认为的,而没有什么依据表明这样用有什么不好,反正我不敢发言,神仙打架瑟瑟发抖。文章源自JAVA秀-https://www.javaxiu.com/42717.html

不过我个人倾向于 Brian Goetz,我觉得 Optional 的用处就是逻辑处理的时候避免判空,仅此而已,所以 POJO 本该如何还是如何,Optional 应该交由逻辑处理代码来用。文章源自JAVA秀-https://www.javaxiu.com/42717.html

好了,把 Optional 的方法都讲完了,可以看到还是很简单的,也没有什么骚操作,比看并发包的简单多了。文章源自JAVA秀-https://www.javaxiu.com/42717.html

总结

总结下来 Optional 主要是简化一系列判空操作,执行过程是一条龙走到底的,你有几个 filter 和 map 不论得到的值空不空,都是执行到底包括 orElse 的逻辑。文章源自JAVA秀-https://www.javaxiu.com/42717.html

再提一个题外话,在 oracle 官网上我看到一篇关于 Optional 的文章,上面写道:文章源自JAVA秀-https://www.javaxiu.com/42717.html

像 Groovy 是利用 ?. 来避免判空的,例如这个代码:文章源自JAVA秀-https://www.javaxiu.com/42717.html

String version = computer?.getSoundcard()?.getUSB()?.getVersion();

后面写了个 note: 请注意,它很快也将被包含在c#中,它曾被提议用于Java SE 7,但没有在那个版本中实现。文章源自JAVA秀-https://www.javaxiu.com/42717.html

咱也不知道为啥没被接受,反正我觉得上面这写法挺清爽的。文章源自JAVA秀-https://www.javaxiu.com/42717.html

再分享下网上看到的一副图:文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

图片文章源自JAVA秀-https://www.javaxiu.com/42717.html

- END -文章源自JAVA秀-https://www.javaxiu.com/42717.html

欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

已在知识星球更新源码解析如下:文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

一个大佬说,Java8的Optional是个鸡肋,我怒了!文章源自JAVA秀-https://www.javaxiu.com/42717.html

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。文章源自JAVA秀-https://www.javaxiu.com/42717.html

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。文章源自JAVA秀-https://www.javaxiu.com/42717.html

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。文章源自JAVA秀-https://www.javaxiu.com/42717.html

文章源自JAVA秀-https://www.javaxiu.com/42717.html

文章有帮助的话,在看,转发吧。谢谢支持哟 (*^__^*)
文章源自JAVA秀-https://www.javaxiu.com/42717.html

阅读原文文章源自JAVA秀-https://www.javaxiu.com/42717.html

继续阅读
速蛙云 - 极致体验,强烈推荐!!!购买套餐就免费送各大视频网站会员!快速稳定、独家福利社、流媒体稳定解锁!速度快,全球上网、视频、游戏加速、独立IP均支持!基础套餐性价比很高!这里不多说,我一直正在使用,推荐购买:https://www.javaxiu.com/59919.html
weinxin
资源分享QQ群
本站是JAVA秀团队的技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
沙海
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定