Optional用法与争议点

news2024/11/13 21:25:43

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后面还有一些本不该被执行的代码执行了。

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

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

相关文章

软件测试8年,却被应届生踩在头上,是应届生太牛了,还是我们太弱了?

前几天有个朋友向我哭诉&#xff0c;说他在公司干了8年的软件测试&#xff0c;却被一个实习生代替了&#xff0c;该何去何从? 这是一个值得深思的问题&#xff0c;作为职场人员&#xff0c;我们确实该思考&#xff0c;我们的工作会被实习生代替吗?这是一个很尖锐的问题&…

MFC基于对话框——仿照Windows计算器制作C++简易计算器

目录 一、界面设计 二、设置成员变量 三、初始化成员变量 四、初始化对话框 ​五、添加控件代码 1.各个数字的代码&#xff08;0~9&#xff09; 2.清除功能的代码 3.退格功能的代码 4.加减乘除功能的代码 5.小数点功能的代码 6.正负号功能的代码 7.等于功能的代码…

算法day42|背包问题

目录 01背包问题 二维 01背包问题 一维 416. 分割等和子集 背包问题分为&#xff1a;01背包&#xff0c;完全背包&#xff0c;多种背包01背包指的是有n种物品&#xff0c;每种物品只能取一个完全背包指的是有n种物品,每种物品可以取无限个多种背包指的是有n种物品&#xff0c;每…

公众号网课搜题接口

公众号网课搜题接口 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&#xff08;点击…

常用的在线工具网站

1&#xff0c;在线Photoshop软件 https://www.uupoop.com/ PS在线图片编辑器是一个专业精简的在线ps图片照片制作处理软件工具,绿色免安装,免下载,直接在浏览器打开就可用它修正,调整和美化图像。 2&#xff0c;bilibili视频编辑器 https://bilibili.clipchamp.com/ 由哔哩哔哩…

(保姆级)国内1块钱注册火爆全网的OpenAI-ChatGPT机器人

下面有给出完整的注册流程。首先介绍一下它是什么&#xff0c;如果只想看注册往下翻&#xff01; 1块钱注册火爆全网的OpenAI-ChatGPT机器人OpengAI-ChatGPT能做什么如何注册1块钱收取验证码使用注册的账号登录ChatGPTOpengAI-ChatGPT能做什么 我作为一个程序员用了一段时间&a…

金蝶云星空生产管理(冲刺学习)

物料“基本”和“生产”相关属性字段介绍 物料属性&#xff1a;生产中常用的物料属性包括自制、委外、外购、虚拟、配置、特征。 自制&#xff1a;一般是指由企业自己生产的物料&#xff0c;一般会建BOM、生产订单&#xff1b; 委外&#xff1a;是指委托给其他加工单位进行加工…

DevTools 无法加载来源映射:无法加载 chrome-extension: 警告的原因以及如何去除(全网最全 最详细解决方案)

是类似这样的一个警告。每次都有看着还是挺难受的。 这个警告的原因是你的浏览器插件造成的。例如警告已经很明确的告诉你是chrome-extension&#xff0c;也就是谷歌插件的问题。后面的字符串其实就是这个插件的id。 chrome-extension://cfhdojbkjhnklbpkdaibdccddilifddb/br…

QT笔记——QSlider滑动条滚轮事件和点击鼠标位置事件问题

需求&#xff1a;我们需要对一个滑动条 滚轮事件 和 点击到滑动条的位置 实时显示 问题&#xff1a;其中在做的时候遇到了很多的问题&#xff0c;一开始感觉很简单&#xff0c;现在将这些问题记录下来 ui图&#xff1a; 问题1&#xff1a;处理QSlider 滚轮事件的时候 这里有…

AlphaFold2源码解析(8)--模型之三维坐标构建

AlphaFold2源码解析(8)–模型之三维坐标构建 这个模块我们讲解AlphaFold的Structure module模块&#xff0c;该结构模块将蛋白质结构的抽象表示映射为具体的三维原子坐标。 Evoformer的单一表征被用作初始单一表征siinitial{s^{initial}_i }siinitial​&#xff0c;siinitial∈…

同步整流 降压恒流 输入4-40V 功率可达40W 电流3.6A 原理图

◆PCB 布线参考PCB 布局应遵循如下规则以确保芯片的正常工作。1:功率线包括地线&#xff0c;LX线和VIN线应该尽量做到短、 直和宽。2:输入电容应尽可能靠近芯片管脚&#xff08;VIN 和 &#xff09;。输入电源引脚可增加一个 0.1uF 的陶瓷电容以增强芯片的抗高频噪声能力。3:功…

小迪-day13(MySQL注入)

一、information_schema information_schema 数据库跟 performance_schema 一样&#xff0c;都是 MySQL 自带的信息数据库。其中 performance_schema 用于性能分析&#xff0c;而 information_schema 用于存储数据库元数据(关于数据的数据)&#xff0c;例如数据库名、表名、列…

信号和电源隔离的有效设计技术

介绍 如今&#xff0c;电子产品设计师比以往任何时候都更面临着一系列共同的目标&#xff1a;实现更高的吞吐量、更高的分辨率、更高效的系统和缩短上市时间。在工业自动化、医疗电子或电信系统等领域&#xff0c;通常需要电隔离多个信号&#xff0c;以使子系统能够共享数据或…

农民歌唱家大衣哥外出商演,大衣嫂在家晒麦子,真是一对金童玉女

在中国华语乐坛&#xff0c;曾经有很多对模范夫妻&#xff0c;比如说任静和付笛声&#xff0c;他们也是音乐领域的金童玉女。其实大家都忽略了一对夫妻&#xff0c;农民歌唱家大衣哥&#xff0c;和他的结发妻子玉华&#xff0c;同样是中国华语乐坛的骄傲。 只是因为大衣哥过于低…

计算机网络复习(一~三)

第一章 基本概念 1-01.计算机网络可以向用户提供哪些服务&#xff1f; 答&#xff1a;例如音频&#xff0c;视频&#xff0c;游戏等&#xff0c;但本质是提供连通性和共享这两个功能。连通性&#xff1a;计算机网络使上网用户之间可以交换信息&#xff0c;好像这些用户的计算…

RDPCrystal EDI SDK 10.0.4.X Crack

关于 RDPCrystal EDI 库 使用 .NET、NodeJS、JavaScript 或 .NET Core 创建、查看和验证 EDI 数据。 RDPCrystal EDI 库是一套 EDI 组件&#xff08;.NET、NodeJS/JavaScript 和 .NET Core&#xff09;&#xff0c;可以创建和操作任何 X12 标准文件。功能包括解析、连接、拆分、…

【Unity】填坑,Unity接入Epic Online Service上架Epic游戏商城

EOS SDK For Unity地址&#xff1a;https://github.com/PlayEveryWare/eos_plugin_for_unity_upm Epic是虚幻游戏引擎开发商&#xff0c;2018年12月Epic宣布推出Epic游戏商城至今刚好三年&#xff0c;Epic将平台分成定为12%(远低于当时Steam的30%)&#xff0c;并且频繁推出各种…

每天一个面试题:四种引用,弱引用防止内存泄漏

每天一个面试题&#xff1a;四种引用四种引用基本介绍实例Demo- 虚引用弱引用防止内存泄漏弱引用Debug分析源码开始全新的学习&#xff0c;沉淀才会有产出&#xff0c;一步一脚印&#xff01; 面试题系列搞起来&#xff0c;这个专栏并非单纯的八股文&#xff0c;我会在技术底层…

ZStack出品|制造业专属的VMware迁移方案长啥样?

导读&#xff1a;在国家大力推动信息技术自主化的背景下&#xff0c;制造业也在积极寻找自身信息化改革的路线。作为信息化技术的基石&#xff0c;虚拟化基础架构替换迫在眉睫。本文将从技术层面详细介绍VMware迁移至 ZStack Cloud 云平台的方案&#xff0c;助力制造业实现“信…

阿里P9整理分享的亿级流量Java高并发与网络编程实战PDF

前言 有人调侃我们说&#xff1a; 程序员不如送外卖。送外卖是搬运食物&#xff0c;自己是搬运代码&#xff0c;都不产出新的东西……透支体力&#xff0c;又消耗健康&#xff0c;可替代性极强&#xff0c;30岁之后就要面临被优化的危险……想跳槽&#xff0c;但是更高的平台…