当前位置: 首页 > news >正文

项目中别用 “! = null“ 做判空了

问题

为了避免空指针调用,我们经常会看到这样的语句:

if (someobject != null) {someobject.doCalc();}

最终,项目中会存在大量判空代码,丑陋繁杂。。。如何避免这种情况?是否滥用了判空?
最终,项目中会存在大量判空代码,丑陋繁杂。。。如何避免这种情况?是否滥用了判空?

精华回答

这是初、中级程序猿经常会遇到的问题。他们总喜欢在方法中返回null,因此,在调用这些方法时,也不得不去判空。另外,也许受此习惯影响,他们总潜意识地认为,所有的返回都是不可信任的,为了保护自己程序,就加了大量的判空。

吐槽完毕,回到这个题目本身:

进行判空前,请区分以下两种情况:

1、null 是一个有效有意义的返回值(Where null is a valid response in terms of the contract; and)

2、null是无效有误的(Where it isn’t a valid response.)

你可能还不明白这两句话的意思,不急,继续往下看,接下来将详细讨论这两种情况。

先说第2种情况

null就是一个不合理的参数,就应该明确地中断程序,往外抛错误。这种情况常见于api方法。例如你开发了一个接口,id是一个必选的参数,如果调用方没传这个参数给你,当然不行。你要感知到这个情况,告诉调用方“嘿,哥们,你传个null给我做甚"。

相对于判空语句,更好的检查方式有两个

(1)assert语句,你可以把错误原因放到assert的参数中,这样不仅能保护你的程序不往下走,而且还能把错误原因返回给调用方,岂不是一举两得。(原文介绍了assert的使用,这里省略)

(2)也可以直接抛出空指针异常。上面说了,此时null是个不合理的参数,有问题就是有问题,就应该大大方方往外抛。

第1种情况会更复杂一些。

这种情况下,null是个”看上去“合理的值,例如,我查询数据库,某个查询条件下,就是没有对应值,此时null算是表达了“空”的概念。

这里给一些实践建议:

1、假如方法的返回类型是collections,当返回结果是空时,你可以返回一个空的collections(empty list),而不要返回null,这样调用侧就能大胆地处理这个返回,例如调用侧拿到返回后,可以直接print list.size(),又无需担心空指针问题。(什么?想调用这个方法时,不记得之前实现该方法有没按照这个原则?所以说,代码习惯很重要!如果你养成习惯,都是这样写代码(返回空collections而不返回null),你调用自己写的方法时,就能大胆地忽略判空。
2、返回类型不是collections,又怎么办呢?

那就返回一个空对象(而非null对象),下面举个“栗子”,假设有如下代码:

public interface Action {void doSomething();}public interface Parser {Action findAction(String userInput);}

其中,Parse有一个接口FindAction,这个接口会依据用户的输入,找到并执行对应的动作。假如用户输入不对,可能就找不到对应的动作(Action),因此findAction就会返回null,接下来action调用doSomething方法时,就会出现空指针。

解决这个问题的一个方式,就是使用Null Object pattern(空对象模式)

改造后

类定义如下,这样定义findAction方法后,确保无论用户输入什么,都不会返回null对象。

public class MyParser implements Parser {private static Action DO_NOTHING = new Action() {public void doSomething() { /* do nothing */ }};public Action findAction(String userInput) {// ...if ( /* we can't find any actions */ ) {return DO_NOTHING;}}}

对比下面两份调用实例

1、冗余:每获取一个对象,就判一次空

Parser parser = ParserFactory.getParser();
if (parser == null) {// now what?// this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {// do nothing} else {action.doSomething();}

精简

ParserFactory.getParser().findAction(someInput).doSomething();

因为无论什么情况,都不会返回空对象,因此通过findAction拿到action后,可以放心地调用action的方法。

其他回答精选:

1、如果要用equal方法,请用object<不可能为空>.equal(object<可能为空>))

例如使用:

"bar".equals(foo)

而不是

foo.equals("bar")

2、Java8或者guava lib中,提供了Optional类,这是一个元素容器,通过它来封装对象,可以减少判空。不过代码量还是不少。不爽。

3、如果你想返回null,请停下来想一想,这个地方是否更应该抛出一个异常。

相关文章:

项目中别用 “! = null“ 做判空了

问题 为了避免空指针调用&#xff0c;我们经常会看到这样的语句: if (someobject ! null) {someobject.doCalc();}最终&#xff0c;项目中会存在大量判空代码&#xff0c;丑陋繁杂。。。如何避免这种情况&#xff1f;是否滥用了判空&#xff1f; 最终&#xff0c;项目中会存在…...

MySQL数据库——MySQL子查询

子查询是 MySQL 中比较常用的查询方法&#xff0c;通过子查询可以实现多表查询。子查询指将一个查询语句嵌套在另一个查询语句中。子查询可以在 SELECT、UPDATE 和 DELETE 语句中使用&#xff0c;而且可以进行多层嵌套。在实际开发时&#xff0c;子查询经常出现在 WHERE 子句中…...

工具链和其他-超级好用的web调试工具whistle

目录 whistle介绍 整体结构 能力 规则 6个使用场景示例 1.修改Host 2.代理 3.替换文件&#xff08;线上报错时&#xff09; 4.替换UA 5.远程调试 6.JS注入 互动 whistle介绍 整体结构 安装&#xff1a; npm install whistle -g cli&#xff1a;whistle help 启动…...

ROS第四十三节——定位

https://download.csdn.net/download/qq_45685327/87725276 1.新建launch文件 关于launch文件的实现&#xff0c;在amcl功能包下的example目录已经给出了示例&#xff0c;可以作为参考&#xff0c;具体实现: roscd amcl ls examples gedit amcl_diff.launch 该目录下会列出两…...

2023年第二十届五一数学建模竞赛题目 C题详细思路

详细思路以及发布视频版&#xff0c;大家可以去观看&#xff0c;这里是对应的文字版&#xff0c;内容相差不多。 C题&#xff1a;“双碳”目标下低碳建筑研究 C题的问题设置其实是本次比赛最简单的一道&#xff0c;就是简单的综合评价预测模型。真正提升C题难度的其实是C题的…...

模块化编程原理示意图--CommonJS 模块编程--ES6 模块编程思路分析/图解--三种导出形式--全部代码示例

目录 模块化编程 基本介绍 模块化编程原理示意图 模块化编程分类 CommonJS 模块编程 介绍 应用实例 1. 需求说明 2. 思路分析/图解 3. 代码实现 function.js use.html use.js ES6 模块编程 介绍 需求说明 思路分析/图解 代码实现 common.js use_common.js …...

Ansys Zemax | 如何模拟双折射偏振器件

这篇文章介绍了什么是双折射现象、如何在OpticStudio中模拟双折射 (birefringence)、如何模拟双晶体的双折射偏振器以及如何计算偏振器的消光比。&#xff08;联系我们获取文章附件&#xff09; 什么是双折射现象 一般的光学材料都是均匀的各向同性的&#xff0c;也就是说无论光…...

Java关键字之:this

一、this关键字的使用 1、this可以用来修饰、调用&#xff1a;属性、方法、构造器 2、this修饰属性和方法 this理解为&#xff1a;当前对象 或 当前正在创建的对象 在类的方法中。我们可以使用“this.属性"或”this.方法“的方式。调用当前对象属性或者方法。但是&#…...

嵌入式Linux驱动开发(九)Linux中断

1. Linux中断简介 1&#xff09;中断号 linux内核中使用一个int变量表示中断号。 2&#xff09;申请中断&#xff1a; 该函数可以自动激活中断&#xff0c;但是可能引起睡眠&#xff0c;所以需要小心使用。 int request_irq(unsigned int irq, //要申请中断的中断号irq_ha…...

数据库系统-并发控制

文章目录 一、为什么要并发控制1.2 并发控制解决的问题1.2.1 脏读1.2.2 幻读1.2.3 不可重复读1.2.4 数据丢失问题 二、事务调度及可串行性2.1 事务2.1.1 事务的宏观2.1.2 事务的微观2.1.3 事务的特性 ACID 2.2 事务调度与可串行性2.3 冲突可串行化判定 三、基于封锁的并发控制方…...

Java8 教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Java 8 是oracle公司于2014年3月发布&#xff0c;可以看成是自Java 5 以来最具革命性的版本。Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性。 Java 8入门教程 - 从简单的步骤了解Java…...

从零开始学架构——高可用存储架构

双机架构 存储高可用方案的本质都是通过将数据复制到多个存储设备&#xff0c;通过数据冗余的方式来实现高可用&#xff0c;其复杂性主要体现在如何应对复制延迟和中断导致的数据不一致问题。因此&#xff0c;对任何一个高可用存储方案&#xff0c;我们需要从以下几个方面去进…...

连ChatGPT都不懂的五一调休,到底怎么来的?

今天是周几&#xff1f; 你上了几天班了&#xff1f; 还要上几天班放假&#xff1f; 五一啥安排&#xff1f; 出行的票抢到了吗&#xff1f; 调休到底是谁发明的&#xff1f;&#xff01; 五一劳动节是要劳动吗&#xff1f; 为什么昨天是周一&#xff0c;今天还是周一&a…...

AES工作流程

工作流程 模式 1&#xff1a;加密 ⚫ 复位EN 重置AES模块 ⚫ 设置模式寄存器mode[1:0]00&#xff0c;设置流数据处理模式寄存器CHMOD[1:0] ⚫ 写AES_KEYRx寄存器&#xff0c;CTR和CBC模式下写AES_IVRx寄存器 ⚫ 写EN1&#xff0c;使能AES ⚫ 写AES_DINR 寄存器4次 ⚫ 等待CCF标…...

C++11

C11 统一的列表初始化 在介绍这里的列表初始化之前&#xff0c;首先我认为这是一个比较鸡肋的功能特性&#xff0c;而且使用起来会和之前C98时有些区别。 // 首先可以定义普通的内置类型的变量int x1 1;int x2 { 1 };int x3{ 1 }; // 这样看起来着实有些怪int arry1[] { 1,…...

ubuntu18.04 配置zlmediakit 支持ffmpeg转码记录

1、zlmediakt 默认不支持ffmepg转码&#xff0c;需要在根目录下的CamkeLists.txt里面option(ENABLE_FFMPEG "Enable FFmpeg" OFF) 将OFF改成ON, 删除原有的build目录&#xff0c;sudo mkdir build. cd build,cmake .. 这样在编译生成文件夹release/linux/debug/生…...

H68K配置路由功能

系统环境Armbian ubuntu系统 参考 如何使用Debian/Ubuntu等Linux做软路由&#xff08;物理机版本&#xff0c;非虚拟机容器版&#xff09; - 知乎 https://zhuanlan.zhihu.com/p/587068225 按照他操作的结果,就是只有一个网卡正常 最后一顿操作就出现了我这么个配置 更新源…...

*2.5 迭代法的收敛阶与加速收敛方法

学习目标&#xff1a; 了解迭代法的基本概念和原理。学习者需要理解迭代法的基本概念和原理&#xff0c;包括迭代过程、迭代格式、收敛性等基本概念。 熟练掌握迭代法的收敛阶和收敛速度。学习者需要了解迭代法的收敛阶和收敛速度&#xff0c;掌握如何计算迭代法的收敛阶和收敛…...

仪表板展示 | X-lab开放实验室GitHub开源项目洞察大屏

背景介绍 X-lab开放实验室是一个开源软件产业开放式创新的共同体&#xff0c;由来自国内外著名高校、创业公司、部分互联网与IT企业的专家学者与工程师所构成&#xff0c;目前已在包括开源治理标准制定、开源社区行为度量与分析、开源社区流程自动化、开源全域数据治理与洞察等…...

【c语言】五大内存区域 | 堆区详解

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...