在 Java 8 中避免 Null 检查
如何预防 Java 中著名的 NullPointerException 异常?这是每个 Java 初学者迟早会问到的关键问题之一。而且中级和高级程序员也在时时刻刻规避这个错误。其是迄今为止 Java 以及很多其他编程语言中最流行的一种错误。
Null 引用的发明者 Tony Hoare 在 2009 年道歉,并称这种错误为他的十亿美元错误。
我将其称之为自己的十亿美元错误。它的发明是在1965 年,那时我用一个面向对象语言(ALGOL W)设计了第一个全面的引用类型系统。我的目的是确保所有引用的使用都是绝对安全的,编译器会自动进行检查。但是我未能抵御住诱惑,加入了 Null 引用,仅仅是因为实现起来非常容易。它导致了数不清的错误、漏洞和系统崩溃,可能在之后 40 年中造成了十亿美元的损失。
无论如何,我们必须要面对它。所以,我们到底能做些什么来防止 NullPointerException 异常呢?那么,答案显然是对其添加 null 检查。由于 null 检查还是挺麻烦和痛苦的,很多语言为了处理 null 检查添加了特殊的语法,即空合并运算符 —— 其在像 Groovy 或 Kotlin 这样的语言中也被称为 Elvis 运算符。
不幸的是 Java 没有提供这样的语法糖。但幸运的是这在 Java 8 中得到了改善。这篇文章介绍了如何利用像 lambda 表达式这样的 Java 8 新特性来防止编写不必要的 null 检查的几个技巧。
在 Java 8 中提高 Null 的安全性
我已经在另一篇文章中说明了我们可以如何利用 Java 8 的 Optional 类型来预防 null 检查。下面是那篇文章中的示例代码。
假设我们有一个像这样的类层次结构:
class Outer {
Nested nested;
Nested getNested() {
return nested;
}
}class Nested {
Inner inner;
Inner getInner() {
return inner;
}
}class Inner {
String foo;
String getFoo() {
return foo;
}
}
解决这种结构的深层嵌套路径是有点麻烦的。我们必须编写一堆 null 检查来确保不会导致一个 NullPointerException:
Outer outer = new Outer();if (outer != null && outer.nested != null && outer.nested.inner != null) {
System.out.println(outer.nested.inner.foo);
}
我们可以通过利用 Java 8 的 Optional 类型来摆脱所有这些 null 检查。map 方法接收一个 Function 类型的 lambda 表达式,并自动将每个 function 的结果包装成一个 Optional 对象。这使我们能够在一行中进行多个 map 操作。Null 检查是在底层自动处理的。
Optional.of(new Outer())
.map(Outer::getNested) .map(Nested::getInner) .map(Inner::getFoo) .ifPresent(System.out::println);
还有一种实现相同作用的方式就是通过利用一个 supplier 函数来解决嵌套路径的问题:
Outer obj = new Outer();
resolve(() -> obj.getNested().getInner().getFoo());
.ifPresent(System.out::println);
调用 obj.getNested().getInner().getFoo()) 可能会抛出一个 NullPointerException 异常。在这种情况下,该异常将会被捕获,而该方法会返回 Optional.empty()。
public static <T> Optional<T> resolve(Supplier<T> resolver) {
try {
T result = resolver.get();
return Optional.ofNullable(result);
}
catch (NullPointerException e) {
return Optional.empty();
}
}
请记住,这两个解决方案可能没有传统 null 检查那么高的性能。不过在大多数情况下不会有太大问题。
像往常一样,上面的示例代码都托管在 GitHub。
祝编码愉快!
原文:https://winterbe.com/posts/2015/03/15/avoid-null-checks-in-java/
译文:https://www.oschina.net/translate/avoid-null-checks-in-java
原文作者:Benjamin
译文作者:ostatsu
更多精彩内容也可查看 https://xdclass.net/#/index
在 Java 8 中避免 Null 检查的更多相关文章
- 使用Java8中的Optional类来消除代码中的null检查
简介 Optional类是Java 8新增的一个类,Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException). —— 每个 Java 程序员都非常了解的异常 ...
- Andoid java文件中的Log检查工具
AndroidLogChecker 由于发布软件版本的时候我们需要把Log注释掉,此工具可以检查java类中的Log所在行以及是否已经注释. Github: https://github.com/cu ...
- 避免Java应用中NullPointerException的技巧和最佳实践
Java应用中抛出的空指针异常是解决空指针的最好方式,也是写出能顺利工作的健壮程序的关键.俗话说"预防胜于治疗",对于这么令人讨厌的空指针异常,这句话也是成立的.值得庆幸的是运用一 ...
- Java中有关Null的9件事
对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常 (NPE)的骚扰.连Java的发明者都承认这是他的一项巨大失误.Java为什么要保留null呢?null出现有一段时间了,并且我 ...
- 转!!Java中关于Null的9个解释(Java Null详解)
对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NPE)的骚扰.连Java的发明者都承认这是他的一项巨大失误.Java为什么要保留null呢?null出现有一段时间了,并且我认 ...
- Java中的双重检查锁(double checked locking)
最初的代码 在最近的项目中,写出了这样的一段代码 private static SomeClass instance; public SomeClass getInstance() { if (nul ...
- 关于Java中的Null
什么是Java中的Null? null在Java中是一个非常重要的概念,它最初是为了表示缺少某些东西,例如缺少用户.资源或任何东西而发明出来的.但是这也为Java程序员带来了很多麻烦,比如最常见的空指 ...
- Java 中遇到null 和为空的情况,使用Optional来解决。
Java 中遇到null 和为空的情况,使用Optional来解决 示例代码: package crazy; import java.util.Optional; class Company { pr ...
- Java中的Null是什么?
对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NPE)的骚扰.连Java的发明者都承认这是他的一项巨大失误.Java为什么要保留null呢?null出现有一段时间了,并且我认 ...
随机推荐
- 面试d090305知识点准备01
1.1 类成员访问[jL1] 权限 1.2 写个双线程,计算50内的奇偶数 1.3 打印等腰三角形 1.4 运算符优先级 括号,非正负和自增减(右到左),乘除加减,等于不等于,逻辑与和或,然后 ...
- sqllocaldb 的使用记录
sql脚本是一个文件大约也就几MB,要是有一种文件存储数据就好了,后来了解到了sqllocaldb,但是没有深入研究大概知道有这么一个东西.这次翻出来还是自家小姑姑要做winfrom但是苦于sqlse ...
- Jmeter ExcelDataPreProcessor
Jmeter的预处理器主要是用来在采样器(sample)被执行之前做一些额外的工作,比如参数化等等. 本文写一个例子来说明如何增加一个预处理器,需求如下:我们想在执行采样器前读取Excel文件中的数据 ...
- POJ1047 Round and Round We Go
题目来源:http://poj.org/problem?id=1047 题目大意: 有一些整数具有这样的性质:它的位数为n,把它和1到n的任意一个整数相乘结果的数字会是原数字的一个“环”.说起来比较抽 ...
- htmlunit最具有参考意义项目
### HtmlUnit What? - 项目1 https://gitee.com/dgwcode/spiderTmallTradeInfo - 项目2 https://gitee.com/dgwc ...
- 什么是obj文件?
百度百科: 程序编译时生成的中间代码文件.目标文件,一般是程序编译后的二进制文件,再通过链接器(LINK.EXE)和资源文件链接就成可执行文件了.OBJ只给出了程序的相对地址,而可执行文件是绝对地址. ...
- UVa11093
//当汽车从第i个加油站到第j个加油站无法继续走下去的时候,这时候[i,j]区间的所有加油站都无法作为起点,因为当我们到第k个加油站的时候,起码是带着>=0的油去的,现在不带油直接从第k个开始肯 ...
- Storm概念学习系列 之Worker工作者进程
不多说,直接上干货! Worker工作者进程 工作者进程(Worker)是一个java进程,执行拓扑的一部分任务.一个Worker进程执行一个Topology的子集,它会启动一个或多个Execut ...
- Docker最全教程之使用PHP搭建个人博客站点(二十二)
目录 官方镜像 编写简单的Hello world! 1. 编写Hello world! 2. 编写Dockerfile 3. 构建并运行 4. 直接使用PHP Docker镜像运行PHP脚本 构建自 ...
- SOA框架
SOA是什么 估计很多人都听说过SOA这个词了,但是很多人还是不知道到底什么是SOA.开发人员很容易理解为是一个Web Service,但是这绝对不是SOA,那顶多只能算是SOA的一种实现方法.那么, ...