Objects.requireNonNull 方法说明

在写代码的时候,Idea经常会提醒我们可以使用这个方法来进行参数非空检查, 这个方法的源码也非常简单, 如下所示:

/*** Checks that the specified object reference is not {@code null}. This* method is designed primarily for doing parameter validation in methods* and constructors, as demonstrated below:* <blockquote><pre>* public Foo(Bar bar) {*     this.bar = Objects.requireNonNull(bar);* }* </pre></blockquote>** @param obj the object reference to check for nullity* @param <T> the type of the reference* @return {@code obj} if not {@code null}* @throws NullPointerException if {@code obj} is {@code null}*/
public static <T> T requireNonNull(T obj) {if (obj == null)throw new NullPointerException();return obj;
}

这个方法是 Objects 类的一个静态方法, Objects 类是一个 Java 静态类, 里面包含了很多 Java 工具方法, 其方法都是静态方法, 其类的说明文档如下:

/*** This class consists of {@code static} utility methods for operating* on objects.  These utilities include {@code null}-safe or {@code* null}-tolerant methods for computing the hash code of an object,* returning a string for an object, and comparing two objects.** @since 1.7*/
public final class Objects {...
}

可以看出, 这个类还包括了很多关于类操作的使用工具方法, 例如比较两个类是否相等, 计算类的 Hash Code 等方法, 这个类以后有机会进行学习和介绍.

回到 requireNonNull() 这个方法, 其源码实现非常简单, 只是进行了一个简单的判断, 如果所要判断的元素为 null, 则返回空指针异常 NullPointerException, 否则直接返回对应的对象.

这看上去好像是一个多余的操作, 因为如果我们试图去调用一个空对象的方法, 也会抛出 NullPointerException 运行时异常, 那么我们为什么要多此一举进行这样的一次检查呢? 这一问题在 StackOverflow 上有人进行了解答 Why should one use Objects.requireNonNull?.

看了他们的回答, 总结为以下几点:

首先, 从这个方法的名称可以看出, 这个方法使用的场景是, 我们使用一个对象的方法时, 正常的运行状态应该能保证这个对象的引用非空, 如果这个对象为空了, 那一定是其他某个地方出错了, 所以我们应该抛出一个异常, 我们不应该在这里处理这个非空异常.

其次, 这里涉及到一个很重要的编程思想, 就是 Fail-fast 思想, 翻译过来就是, 让错误尽可能早的出现, 不要等到我们很多工作执行到一半之后才抛出异常, 这样很可能使得一部分变量处于异常状态, 出现更多的错误. 这也是 requireNonNull 这个方法的设计思想, 让错误尽早出现. 使用这个方法, 我们明确的抛出异常, 发生错误时, 我们立刻抛出异常.

StackOverflow 中的一个回答举了一个具体的例子来回答这个问题, 例如有下面这样一个类:

public class Dictionary {private final List<String> words;private final LookupService lookupService;public Dictionary(List<String> words) {this.words = this.words;this.lookupService = new LookupService(words);}public boolean isFirstElement(String userData) {return lookupService.isFirstElement(userData);}        
}public class LookupService {List<String> words;public LookupService(List<String> words) {this.words = words;}public boolean isFirstElement(String userData) {return words.get(0).contains(userData);}
}

这里, 两个类是包含的关系, 传入的 List 参数没有做非空检查. 如果我们一不小心在 Dictionary 的构造方法中传入了 null, 如下所示:

Dictionary dictionary = new Dictionary(null); // exception thrown lately : only in the next statement
boolean isFirstElement = dictionary.isFirstElement("anyThing");

我们在构造时没有任何异常, 但是当我们调用方法时, 会抛出 NPE:

Exception in thread "main" java.lang.NullPointerExceptionat LookupService.isFirstElement(LookupService.java:5)at Dictionary.isFirstElement(Dictionary.java:15)at Dictionary.main(Dictionary.java:22)

JVM 告诉我们, 在执行 return words.get(0).contains(userData) 这条语句时, 发生了异常, 但是这个异常非常不明确, 从报错信息来看, 有多种可能会导致这个异常发生, 是因为 words 为空, 还是 words.get(0) 为空? 或者两者都为空? 这都是不明确的. 同时, 我们也无法确定是在这两个类的哪个环节出了错, 这些都是不明确的, 给我们程序 debug 造成了很大的困难.

然而, 当我们使用如下方式实现:

public Dictionary(List<String> words) {this.words = Objects.requireNonNull(words);this.lookupService = new LookupService(words);
}

按照这种实现方式, 在我们执行构造方法时, 就会明确抛出错误.

// exception thrown early : in the constructor 
Dictionary dictionary = new Dictionary(null);// we never arrive here
boolean isFirstElement = dictionary.isFirstElement("anyThing");
Exception in thread "main" java.lang.NullPointerExceptionat java.util.Objects.requireNonNull(Objects.java:203)at com.Dictionary.(Dictionary.java:15)at com.Dictionary.main(Dictionary.java:24)

这样我们进行 debug 时就明确很多, 少走很多弯路.

除此之外, 这个方法的作用也是一个明确和不明确的区别, 使用这个方法表示我们明确进行了这个判断, 其实与我们自己使用 if-else 进行判断是一样的, 只是这个工具类简化了这样的操作, 让我们的代码看上去更加简洁, 可读性更强.

此外, requireNonNull 方法有一个重载方法, 可以提供一个报错信息, 以供我们 debug 的时候显示. 我们使用这个引用的时候, 应当保证非空, 如果不然, 会抛出异常告诉我们其他地方出错了, 这里出现了空指针异常. 这个方法重载的实现如下:

/*** Checks that the specified object reference is not {@code null} and* throws a customized {@link NullPointerException} if it is. This method* is designed primarily for doing parameter validation in methods and* constructors with multiple parameters, as demonstrated below:* <blockquote><pre>* public Foo(Bar bar, Baz baz) {*     this.bar = Objects.requireNonNull(bar, "bar must not be null");*     this.baz = Objects.requireNonNull(baz, "baz must not be null");* }* </pre></blockquote>** @param obj     the object reference to check for nullity* @param message detail message to be used in the event that a {@code*                NullPointerException} is thrown* @param <T> the type of the reference* @return {@code obj} if not {@code null}* @throws NullPointerException if {@code obj} is {@code null}*/
public static <T> T requireNonNull(T obj, String message) {if (obj == null)throw new NullPointerException(message);return obj;
}

例如, 我们在 Android 中可以按照如下方式使用:

String username = Objects.requireNonNull(textInputLayoutUsername.getEditText(), "TextInputLayout must have an EditText as child").getText().toString();

这是一个从 TextInpuLayout 获取用户输入内容的方法, 通常使用 TextInputLayout 包裹一个 EditText 来接收用户输入, 因此我们需要通过 TextInputLayoutgetEditText() 方法来获取对应的 EditText, 如果我们布局有问题, 则该方法可能返回 null, 因此我们可以通过上述方法, 抛出一个明确异常, 如果运行时出现问题, 我们也可以很快知道是因为我们 TextInputLayout 无法获取 EditText 而出错的.

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

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

相关文章

Java service层获取HttpServletRequest工具类的方法

大家都知道 能在Controller/action层获取HttpServletRequest &#xff0c;但是这里给大家备份的是从代码内部service层获取HttpServletRequest工具类。 具体如下&#xff1a; package com.base.common.sessionutils; import javax.servlet.http.HttpServletRequest; import j…

正则表达式发明者_浅谈正则表达式背后的基本原理

一、写在前面搞编程的都知道正则表达式是什么东西&#xff0c;这里就不多啰嗦了&#xff0c;需要强调的是&#xff0c;这篇文章并不是教你怎么去使用用正则表达式&#xff0c;正则表达式的语法并不是本文的重点&#xff0c;这篇文章的目的就是剥开正则表达式的语法糖&#xff0…

Java8 - 使用 Comparator.comparing 进行排序

使用外部比较器Comparator进行排序 当我们需要对集合的元素进行排序的时候&#xff0c;可以使用java.util.Comparator 创建一个比较器来进行排序。Comparator接口同样也是一个函数式接口&#xff0c;我们可以把使用lambda表达式。如下示例&#xff0c; package com.common;im…

cairo填充_Cairo 图形指南 (5) —— 形状与填充

这一部分&#xff0c;讲述一些基本的以及较为高级的形状绘制及其纯色 (solid color)、图案 (pattern) 与渐变 (gradient) 填充方法。基本形状Cairo 提供了几个用于绘制基本形状的函数。#include#include#includestatic gbooleanon_expose_event (GtkWidget * widget,GdkEventEx…

java集合进行排序的两种方式

java集合的工具类Collections中提供了两种排序的方法,分别是: Collections.sort(List list)Collections.sort(List list,Comparator c) 第一种称为自然排序,参与排序的对象需实现comparable接口,重写其compareTo()方法,方法体中实现对象的比较大小规则,示例如下: 实体类:(基本…

ubuntu编写python脚本_python在ubuntu中的几种方法(小结)

通过ubuntu官方的apt工具包安装通过PPA(Personal Package Archive) 的apt工具包安装通过编译python源代码安装通过ubuntu官方的apt工具包安装安装完成后&#xff0c; 可以用下面的命令进行确认从PPA(Personal Package Archives) 安装apt工具包类似使用apt工具包安装python的工…

Java中String类中compareTo( )方法

compareTo方法是比较简单的&#xff0c;我们可以直接看其源码: 源码如下&#xff1a; public int compareTo(String anotherString) {int len1 value.length;int len2 anotherString.value.length;int lim Math.min(len1, len2);char v1[] value;char v2[] anotherString…

python elif可以单独使用_Python的elif语句怎么用

else和elif语句也可以叫做子句&#xff0c;因为它们不能独立使用&#xff0c;两者都是出现在if、for、while语句内部的。else子句可以增加一种选择&#xff1b;而elif子句则是需要检查更多条件时会被使用&#xff0c;与if和else一同使用&#xff0c;elif是else if 的简写。if和…

SpringMVC接收哪些类型参数参数

支持的数据类型&#xff1a; 基本类型参数&#xff1a; 包括基本类型和 String 类型 POJO 类型参数&#xff1a; 包括实体类&#xff0c;以及关联的实体类 数组和集合类型参数&#xff1a; 包括 List 结构和 Map 结构的集合&#xff08;包括数组&#xff09; SpringMVC …

禁用当前的账户win7_系统小技巧:服务客人 开启Windows 10来宾账户

出于安全考虑&#xff0c;Windows 10默认以管理员账户登录&#xff0c;没有开启来宾账户。但对于那些只需在电脑上浏览网页或收看电子邮件的用户&#xff0c;给他们开启来宾账户非常必要。来宾权限或账户的开启&#xff0c;可以通过下面的两种方法。1. 通过系统设置 开启来宾权…

Java之接口的静态方法的定义和使用

格式如下&#xff1a;&#xff08;就是将abstract或者default换成ststic即可&#xff0c;带上方法体&#xff09; public static 返回值类型 方法名称&#xff08;参数列表&#xff09;{方法体----}代码如下&#xff1a; //定义一个接口 public interface MyInterfaceStatic …

三阶魔方还原步骤图_三阶魔方公式图解、教程

三阶魔方公式、魔方图解、魔方教程&#xff0c;从零基础到精通&#xff01;魔方还原法 Rubics Cube Solution ————先看理论“魔方的还原方法很多精彩内容&#xff0c;尽在百度攻略&#xff1a;https://gl.baidu.com在这里向大家介绍一种比较简单的魔方六面还原方法。这种方…

通俗易懂告诉你CPU/GPU是什么?

通俗易懂告诉你CPU/GPU是什么&#xff1f; CPU CPU( Central Processing Unit, 中央处理器)就是机器的“大脑”&#xff0c;也是布局谋略、发号施令、控制行动的“总司令官”。 CPU的结构主要包括运算器&#xff08;ALU, Arithmetic and Logic Unit&#xff09;、控制单元&a…

mysql正在加载_mysql 数据库基本操作

CREATE TABLE classes(id INT PRIMARY KEY AUTO_INCREMENT COMMENT班级表id,name VARCHAR(20) COMMENT班级名称);运行DESCRIBE classes;--------------------------------------------------------| Field | Type | Null | Key | Default | Extra |---------------------------…

CPU和GPU的区别是什么?

CPU是一种微处理器&#xff0c;用于执行程序根据操作(如算术、逻辑、控制和输入-输出)给出的指令。相反&#xff0c;GPU最初设计用于在电脑游戏中渲染图像。CPU强调低延迟&#xff0c;而GPU则强调高吞吐量。 CPU Vs GPU 内容 比较表格定义区别关键不同结论 1. 比较表格 从上…

乌班图配置mysql Java_Ubuntu准备+MySQL+Java

Linux服务器准备1 . 安装Ubuntu系统2 . 修改root用户密码sudo passwd root #修改root账户密码logout # 退出当前账号并重新登录#如果需要关机使用 halt 命令3 . 更新所有Linux的开发包apt-get update4 . 配置相关的编译包apt-get install gcc libpcre3 libpcrecpp* libpcre3-de…

java截取指定字符串中的某段字符

利用字符串的substring函数来进行截取。 其中&#xff0c;substring函数有两个参数&#xff1a; 1、第一个参数是开始截取的字符位置。&#xff08;从0开始&#xff09; 2、第二个参数是结束字符的位置1。&#xff08;从0开始&#xff09; indexof函数的作用是查找该字符串中…

JSON中的JSON.parseArray()、JSON.parseObject()、JSON.tojsonString()

1、JSON.parseObject和JSON.toJSONString JSON.parseObject&#xff0c;是将Json字符串转化为相应的对象&#xff1b;JSON.toJSONString则是将对象转化为Json字符串。在前后台的传输过程中&#xff0c;JSON字符串是相当常用的&#xff0c;这里就不多介绍其功能了&#xff0c;直…

mysql是gplv3,Affero-GPL和GPLv3之间的区别

解决方案Assume the following:You are developing a server side application in GPL. Now this application serves HTML and not an executable which is directly executed on your machine. That means that another guy could take the GPL code, adapt it and does not …

mysql cluster proxy_GitHub - freedaxin/maya: a mysql cluster proxy powered by node.js

maya安装node.js依赖node v0.8最新版&#xff0c;暂不支持更高的node版本&#xff0c;此处以0.8.7版本为例。root安装(官方要求python2.5.2以上)tar -zxf node-v0.8.7.tar.gzcd node-v0.8.7./configure --prefix/usr/local/sinasrv2/makemake install在root环境变量中增加如下两…