Optional用法与争议点

87 篇文章 2 订阅
订阅专栏

Optional用法与争议点

简介

要说Java中什么异常最容易出现,我想NullPointerException一定当仁不让,为了解决这种null值判断问题,Java8中提供了一个新的工具类Optional,用于提示程序员注意null值,并在特定场景中简化代码逻辑。

比如下面一段取深层属性值的代码:

Order order = getOrderById(orderId);
String userCode = "";
if(order != null){
    if(order.getUser() != null){
        if(order.getUser().getUserCode() != null){
            userCode = order.getUser().getUserCode().toUpperCase();
        }
    }
}

这种场景还比较常见,但深层嵌套的if判断,让代码阅读者压力倍增。

看看用Optional后的写法,如下:

Order order = getOrderById(orderId);
String userCode = Optional.ofNullable(order)
    .map(Order::getUser)
    .map(User::getUserCode)
    .map(String::toUpperCase)
    .orElse("")

链式调用的写法,让代码可读性增强了不少,不用判断null,是因为Optional在内部已经做了null值判断了!那我们来看看Optional都有哪些用法吧。

创建Optional

ofNullable()方法 创建一个Optional,传入的值可以是null或不是null。

of()方法 得到一个Optional,明确知道传入的值不是null时用这个,如果传null会报错NullPointerExcepiton。 其实值不为null一般是没必要使用Optional的,这个应该是用于特殊场景,比如方法返回值必须是一个Optional。

empty()方法 得到一个空的Optional,一般也用于返回值必须是Optional的场景。

判空

ifPresent()方法 判断是否有值,注意,这个方法虽然看起来挺好用的,但它不太应该是使用Optional时第一个使用的方法,如下:

if(opt.ifPresent()){
    ...
}
if(obj != null) {
    ...
}

这两个代码除了写法不一样,对于代码可读性方面没有根本区别!

取值

get()方法 获取Optional的值,当没有值时会抛出一个NoSuchElementException异常。

 

同样的,它也不太应该是使用Optional时的第一个使用的方法,因为抛NoSuchElementException与抛NullPointerException并没有太大区别。

orElse方法 没有值时会返回指定的值。

String name = nameOpt.orElse("");

orElseGet方法 同上,不过参数变成了一个提供默认值的lambda函数,这用在取指定值需要一定代价的场景,如下:

BigDecimal amount = amountOpt.orElseGet(() -> calcDefaultAmount());

orElseThrow方法 没有值时抛出一个指定的异常,如下:

Optional<User> userOpt = getUser(userId);
User user = userOpt.orElseThrow(() -> new NullPointerException("userId:" + userId));

可能会有人疑问,你还是抛出了一个NPE异常,和不使用Optional有啥区别?区别是这个NPE异常会告诉你哪个userId查不到数据,方便定位问题,而jvm抛出的NPE是没有这个信息的。

函数式处理

ifPresent(Consumer<? super T> consumer)方法 这个方法和ifPresent()方法不一样,这个方法代表如果Optional有值时,就执行传入的lambda函数,如下:

userOpt.ifPresent((user) -> System.out.printf("%s\n", user.toString()));

filter方法 这个方法用于过滤Optional中的值,若Optional有值,且值满足过滤函数,则返回此Optional,否则返回空Optional。

 

String name = nameOpt.filter(StringUtils::isNotBlank).orElse("");

map方法 这个方法用于转换值,在最前面已经展示过了,若Optional有值,执行map中的lambda函数转换值,如下:

Order order = getOrderById(orderId);
String userCode = Optional.ofNullable(order)
    .map(Order::getUser)
    .map(User::getUserCode)
    .map(String::toUpperCase)
    .orElse("")

Optional还提供了一个flatMap方法,与map方法的区别是,传给flatMap的lambda函数,这个lambda函数的返回值需要是Optional。

Optional争议点

其实到底该不该用Optional,业界还是有不少争议的,一方面是Optional能强迫开发者处理null值,但另一方面是Optional又非常容易滥用,特别是一些开发者拿到Optional之后就直接调用get()ifPresent()方法,这样几乎没解决任何问题,还加重了编码负担。

因此,我的建议是,在你不知道该不该使用Optional的场景,那就先别用。

下面是一些使用Optional的场景参考,如下:

  1. Optional一般用于返回值 Optional大多用于返回值,不推荐用在成员变量或方法参数中。

  2. Optional本身不判null 永远都不要给Optional赋值null,也不要判断Optional本身是否为null,这是因为Optional本来就是解决null的,再引入null就没意思了,这应该成为业界共识。

  3. 集合不使用Optional 因为集合有Collections.emptyList()等更好的处理方法了,没必要再使用Optional。

  4. 函数式处理值 从上面的用法介绍中就能发现,Optional提供了很多lambda函数式处理的方法,如filter、map等,这些是使用Optional时比较推荐使用的,因为Optional能帮你自动处理null值情况,避免NPE异常。

  5. 多层属性获取 前面举过这个代码样例,我觉得这是Optional使用收益最明显的一个场景。

  6. 不返回null胜过返回Optional 返回Optional给调用方,会强制调用方处理null情况,会给调用方增加一些的编码负担,特别是复用度很高的函数。 但如果调用方大多数情况下都不期望获取到null,那应该实现一个这样的方法,要么返回值,要么异常,如下:

/**
 * 查询订单,要么返回订单,要么异常
 */
public Order getOrderByIdOrExcept(Long orderId){
    Order order = orderMapper.getOrderById(orderId);
    if(order == null){
        throw new BizException("根据单号" + orderId + "未查询到订单!");
    }
    return order;
}
​
/**
 * 查询订单,值可能为null
 */
public Optional<Order> getOrderById(Long orderId){
    Order order = orderMapper.getOrderById(orderId);
    return Optional.ofNullable(order);
}

由于后面处理代码依赖订单数据,获取不到订单数据,代码也没法往下走,所以在大多数情况下,选择使用getOrderByIdOrExcept方法更好,即避免了NPE,又避免了增加编码负担!

总结

Optional能解决一些问题,但因为容易滥用而争议很大,因为Optional将null的处理交给调用方了,但大多数情况下,调用方也没办法处理这个null情况,还不如让JVM抛一个NPE异常中止执行,因为如果你用ifPresent的话,还更容易造成逻辑bug导致执行了不该执行的代码。

这和Java的受检查异常是一样的,强制要求调用方处理异常,但又有多少场景的异常是调用方可以处理的呢?这导致开发人员经常滥用catch,对异常处理一把梭了,最后发现catch后面还有一些本不该被执行的代码执行了。

现代C++24- 处理数据类型变化和错误:optional、variant、expected和Herbception
qq_53280238的博客
06-24 538
我们之前已经讨论了异常是推荐的 C++ 错误处理方式。不过,C++ 里有另外一些结构也很适合进行错误处理,今天我们就来讨论一下。
实践中的Optional:重构与优化你的代码
最新发布
拥有必珍惜
08-13 596
OptionalJava 8引入的一个容器类,它位于java.util包下。Optional类是一个可以为null的容器对象,用于解决空指针异常(NullPointerException)的问题。通过明确地使用Optional,程序可以更加清晰地表达一个值可能存在也可能不存在的情况,从而提高代码的健壮性和可读性。随着Optional的广泛使用,社区中逐渐形成了一些最佳实践,但同时也存在一些争议
JDK1.8新特性(八):还在重复写空指针检查代码?赶紧使用Optional吧!
xcbeyond|疯狂源自梦想,技术成就辉煌
08-20 478
前期回顾: JDK1.8新特性(一):JDK1.8究竟有哪些新特性呢 JDK1.8新特性(二):为什么要关注JDK1.8 JDK1.8新特性(三):Lambda表达式,让你爱不释手 JDK1.8新特性(四):函数式接口 JDK1.8新特性(五):Stream,集合操作利器,让你好用到飞起来 JDK1.8新特性(六):Stream的终极操作,轻松解决集合分组、汇总等复杂操作 JDK1.8新特性(七):默认方法,真香,开动!接口?我要升级!! 1、前言 作为一名Java程序员,无论是初入茅庐的菜鸟,还是久经江.
java8新特性,方法引用、Optional、函数式
DCHAO的博客
11-16 609
java8新特性,包括方法引用、Optional
第55项:谨慎返回optional
Coloured_Glaze的博客
07-13 1196
  在Java 8之前,在编写在某些情况下无法返回值的方法时,可以采用两种方法。 你可以抛出异常,也可以返回null(假设返回类型是对象引用类型)。这些方法都不完美。【出现】特殊的情况才应该保留异常(第69项),抛出异常【的成本】是很昂贵的,因为在创建异常时会捕获整个堆栈【的】跟踪【信息】。返回null没有这些缺,但它有自己的缺。如果方法返回null,则客户端必须包含(include【使用】)...
Google Guava与基本工具操作相关的类
Life is for sharing的博客
04-12 559
文章目录1.[使用和避免使用null](https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained)1.1Optional1.1.1创建Optional1.1.2查询方法1.1.3重是什么?1.2便利方法1.3使用示例2.[前置条件](https://github.com/google/guava/wiki/Precond...
Masonry介绍与使用:Autolayout
如鱼得水的专栏
05-15 2087
前言 1 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-iphone3gs时代 window的size固定为(320,480) 我们只需要简单计算一下相对位置就好了 在iphone4-iphone4s时代 苹果推出
less的使用方法
程序员
02-25 1833
少用 减少节,浏览器和第三方的使用。有关常规安装说明和概述,请阅读我们首页上的“减少使用”部分。 V2升级指南 语言变更 现在,颜色在写入时即输出,因此purple保持原样purple且不转换为其十六进制表示形式。 命令行用法 干净的CSS 我们已经删除了对clean CSS的依赖,并将其移至了plugin。这使我们能够: 在不减少发布的情况下更新依赖关系和集成 ...
JVM富有争议的观总结以及一些概念理解
weixin_43203497的博客
12-19 227
JVM富有争议的观总结以及一些概念理解JVM表现根据JDK版本不同具有一定的差异JVM常量池,静态变量等存储的位置与内存图表示内存泄露与内存溢出 JVM表现根据JDK版本不同具有一定的差异 JVM常量池,静态变量等存储的位置与内存图表示 常用的JDK版本JDK1.7与JDK1.8具有无论是1.8新增optional包装类,lamda表达式,Stream类等流式编程还是JVM的内存内存模型都有较大...
go context专题(四)- context 最佳实践和相关争议
Andes Home 千年的塔 -十年技术,风雨兼程
08-31 1173
context的设计思想 context包内Context对象设计的思路不是创建一个对象就直接一杆子到底就传递这个对象 针对每个子goroutine可以自己封装Context对象后在逐层朝后传递。 为什么这么设计? 原因就是不同的goroutine 的需求不一样,传递给子goroutine的可能是: WithCancel WithDeadline WithTimeout WithValu
Java8的 Stream 流的各种用法
没啥简介
05-28 389
Java8 的 Stream 流,加上 Lambda 表达式,可以让代码变短变美,还是变短变丑? 距离Java 8发布已经过去了7、8年的时间,Java 19也发布了。Java 8中关于函数式编程和新增的Stream流API至今饱受“争议”。 如果你不曾使用Stream流,那么当你见到Stream操作时一定对它发出过鄙夷的声音,并在心里说出“这都写的什么玩意儿”。 如果你热衷于使用Stream流,那么你一定被其他人说过它可读性不高,甚至在codereview时被要求改用for循环操作,更甚至被写入公司不规范
C++17:大海迷航 缺省比较 “太空船”运算符 统一调用语法 运算符 网络库 条件的显式测试 文件系统 并行 STL
万有文的博客
04-27 757
在经过 C++14 这个小版本标准之后,C++17 [Smith 2017] 原本被看作是一个大版本。C++17 有很多新的特性,但没有一个我认为称得上重大。尽管我们已经有给 C++11 和 C++14 带来成功的工作流程,标准社区也更丰富、更强大、更热情,但对于 C++17 的关键问题是:为什么所有的辛劳却没有带来更显著的改进?C++17 作为一个重要的标准更新,确实引入了许多新的特性和改进,但相对于之前的 C++11 和 C++14,它可能没有带来那种一眼就能看到的“重大”改变。
Java可选参数
最佳 Java 编程
06-11 2786
Java类中设计方法时,某些参数对于其执行而言可能是可选的。 无论是在DTO,胖模型域对象还是简单的无状态服务类中,可选方法参数都是常见的。 从本文中, 您将学习如何在Java中处理可选参数 。 我们将专注于常规方法,带有可选字段的类构造函数,并快速查看所讨论主题的不良做法。 我们将停下来看一下Java 8 Optional,并评估它是否符合我们的需求。 让我们开始吧。 1.可选...
vue组件中重新渲染的3种方式
热门推荐
Andrew_Chenwq的博客
08-26 1万+
因为vue是通过虚拟Dom算法来判断元素的变化,是否变化的核心是通过判断新旧元素的key值是否变化。如果你的key是变化的,则重新渲染该元素,如果key没变,则不会重新渲染。的时候,当前条件块里包含的元素会被销毁,如果包含的是组件,则组件对应的生命周期函数(的时候,当前条件块里的元素会被重建,如果包含的是组件,则组件对应的生命周期函数(属性,然后在需要重新渲染的时候,改变key的值就行。等),计算属性,watch等会执行,相当于重新渲染。所以如果你想让你的组件重新渲染,你给组件加上。...
Redis脑裂现象及解决方案
Andrew_Chenwq的博客
10-24 9022
Redis脑裂可以采用min-slaves-to-write和min-slaves-max-lag合理配置尽量规避,但无法彻底解决,Redis脑裂最本质的问题是主从集群内部没有共识算法来维护多个节的强一致性,它不像Zookeeper那样,每次写入必须大多数节成功后才算成功,当脑裂发生时,Zookeeper节被孤立,此时无法写入大多数节,写请求会直接失败,因此Zookeeper才能保证集群的强一致性。
十几个大表left join的大SQL查询优化
Andrew_Chenwq的博客
01-16 6764
十几个大表left join的大SQL查询优化 问题 十几个表关联查询,有子查询,并表和left join表查询,由于近期上了生产,每天都有几万条应用,查询一个星期内的数据,用了几十分钟,导致触发熔断机制 获取生产环境中的sql 下载日志 获取到执行的sql 替换参数 得到完整的带参数的sql 测试环境复现失败 在测试环境上未能复现成功,但是上线就会出现这个问题 让测试结构复现数据,不可行,数据成分不一致,可能效果完全不同 并且有那么多表,要进行构造数据也是很麻烦的 最后是去现网导出相关表的数据,
java数据安全
Andrew_Chenwq的博客
10-24 4972
数据安全 保证数据安全 需要解决三个问题: 机密性、完整性、身份验证(抗抵赖性) 机密性:传输内容非明文,即使数据被外界截获,也不能被他人解释或破解 完整性:传输过程中内容不能够被篡改,若信息被篡改或不完整,接收方能够得知 身份验证(抗抵赖性):接收方能够验证数据的实际发送方,确保数据不是被人“冒名顶替”而伪造的 举例 甲、乙双方军队攻打丙方,丙方比较强大,因此甲乙双方必须使用合理的配合战术,并且一起进攻,才能取胜,而甲乙双方不再一个地方,他们必须秘密通信 当甲方军师研究好配合战术并确定了进攻时
【mysql】delete from命令使用别名
Andrew_Chenwq的博客
01-07 3740
【mysql】delete from命令使用别名 我们平时使用delete from 进行删除数据库表中的数据 语法 delete from table_name where [clause] 使用别名注意 但是我们会在使用别名的时候出现错误,在oracle中我们可以这样使用 delete from table_name t where t.id = #{id} 但是这种写法在mysql中会报错,【you have an error in your sql syntax;check
Optional用法
03-22
OptionalJava 8引入的一个类,用于解决空指针异常的问题。... - 使用`flatMap(mapper)`方法对Optional对象中的值进行映射转换,返回一个新的Optional对象,但是如果mapper返回的是Optional对象,则不会嵌套包装。
写文章

热门文章

  • Consider defining a bean of type问题解决 51247
  • ES学习看这一篇文章就够了 16066
  • vue组件中重新渲染的3种方式 13703
  • 完美解决Column ‘xxx‘ in field list is ambiguous问题 12333
  • 一台电脑如何配置两个Jdk,然后任意切换使用? 9136

分类专栏

  • JAVA基础工作中实际总结 410篇
  • 编程学习 491篇
  • java错误分析 23篇
  • 软件 13篇
  • Java全套学习计划 18篇
  • 产品 10篇
  • 工具类软件 13篇
  • JAVA面试知识体系实战总结 28篇
  • 信息安全 4篇
  • 工作总结 87篇
  • SVN相关 6篇
  • Maven在eclipse中配置 1篇
  • 面试技巧 154篇
  • Java环境配置 3篇
  • Linux 3篇
  • 互联网创业 4篇
  • 数据库相关 6篇
  • idea项目中总结 4篇
  • oracle以及sql 11篇

最新评论

  • java后台怎么返回blob格式的文件流

    小王毕业啦: 博主的这篇文章让我对java后台返回blob格式的文件流有了更深入的了解,文中详细描述了后端返回blob文件流的步骤和方法,让我受益匪浅。博主的文章写作水平很高,逻辑清晰,让我在阅读过程中很容易理解和吸收。希望博主能够继续分享更多有价值的文章,让我们能够持续学习和成长。感谢博主的辛苦分享和支持!

  • java epoll网络编程

    CSDN-Ada助手: 推荐 Java 技能树:https://edu.csdn.net/skill/java?utm_source=AI_act_java

  • JavaWeb入门看这一篇文章就够了

    monbry: 言简意赅,深度好文

  • Consider defining a bean of type问题解决

    坐看昀起: 谢谢老哥

  • 深入解析java.lang.IllegalStateException异常

    小王毕业啦: 博主的文章真是太赞了!通过深入解析java.lang.IllegalStateException异常,我对这个主题有了全新的认识。文章中的细节描写非常到位,让我感受到了博主的深厚功底和专业知识。期待博主未来能够持续分享更多这样有价值的好文,同时也希望能够得到博主的指导,共同进步。非常感谢博主的分享和支持,让我在学习道路上受益匪浅!

大家在看

  • Shell中 ()、(())、[]、[[]]、{} 的作用
  • Linux下的进程的认识
  • 最新版今日头条独家内部玩法,单号轻松简单日入2张
  • 基于nodejs+vue小说网站[开题+源码+程序+论文]计算机毕业设计
  • 中断-MCU

最新文章

  • 架构师的七大核心能力
  • 开发易忽视的问题:InnoDB 行锁设计与实现
  • 架构之道:如何有效控制对象访问权
2024
09月 19篇
08月 16篇
07月 29篇
06月 16篇
05月 9篇
04月 22篇
03月 25篇
02月 17篇
01月 24篇
2023年299篇
2022年233篇
2021年86篇
2020年11篇
2019年27篇
2018年16篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT枫斗者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家商场美陈提案讲解呈贡玻璃钢雕塑设计制作咨询盐城玻璃钢民俗雕塑设计呈贡玻璃钢雕塑的设计贵不贵玻璃钢雕塑产地美陈商场有没有安踏玻璃钢卡通雕塑流程玻璃钢 雕塑濮阳不锈钢人物玻璃钢雕塑厂家河南常见商场美陈制造电动玻璃钢雕塑南京雕塑玻璃钢玻璃钢花盆栽植物阜阳玻璃钢雕塑加工厂家德阳玻璃钢蔬菜雕塑厂家江苏透明玻璃钢雕塑工厂弥勒市玻璃钢雕塑设计生产商南京铁艺花架玻璃钢花盆浮雕玻璃钢雕塑图片呈贡定做玻璃钢雕塑厂家特别推荐河北装饰商场美陈制造政和玻璃钢花盆花器大象玻璃钢雕塑哪家专业雕塑翻玻璃钢过程重庆佛像玻璃钢雕塑价位玻璃钢几何雕塑玻璃钢雕塑成品价值宁夏抽象人物玻璃钢雕塑哪家好郑州抽象玻璃钢卡通雕塑制作工艺品玻璃钢卡通雕塑设计香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化