Java8 新特性 | 如何风骚走位防止空指针异常
文章整理翻译自 https://winterbe.com/posts/2015/03/15/avoid-null-checks-in-java/
文章首发于个人网站: https://www.exception.site/java8/java8-avoid-null-check
要说 Java 编程中哪个异常是你印象最深刻的,那 NullPointerException 空指针可以说是臭名昭著的。不要说初级程序员会碰到,
即使是中级,专家级程序员稍不留神,就会掉入这个坑里。
Null 引用的发明者 Tony Hoare 曾在 2009 年作出道歉声明,声明中表示,到目前为止,空指针异常大约给企业已造成数十亿美元的损失。
下面是 Tony Hoare 的原话:
我将 Null 引用的设计称为是一个数十亿美元的错误。1965 那年,我正在用面向对象语言(ALGOL W) 设计首个功能全面的系统。当时我的考量是,确保所有被使用的引用都是安全的,编译器会自动进行检查。但是,我没有抵住诱惑,加入了 Null 引用,仅仅是为了实现起来省事。这之后,它导致了数不清的 bug、错误和系统崩溃,也为企业导致了不可估量的损失。
事已至此,我们必须学会面对它。So, 我们要如何防止空指针异常呢?
唯一的办法就是对可能为 Null 的对象添加检查。但是 Null 检查是繁琐且痛苦的。所以一些比较新的语言为了处理 Null 检查,特意添加了特殊的语法,如空合并运算符。
不幸的是,在老版本的 Java 中并没有提供这样的语法糖。Java8 中在这方面做了改进。所以,这篇文章就特意来介绍一下如何在 Java8 中利用新特性来编写防止 NullPointerException的发生。
Java8 中如何加强对 Null 对象的检查?
在上篇文章 Java8 新特性指导手册 中简单的提了一下如何通过 Optional 类来对对象做空校验。接下来,我们再细说一下:
在业务系统中,对象中嵌套对象是经常发生的场景,如下示例代码:
// 最外层对象
class Outer {
Nested nested;
Nested getNested() {
return nested;
}
}
// 第二层对象
class Nested {
Inner inner;
Inner getInner() {
return inner;
}
}
// 最底层对象
class Inner {
String foo;
String getFoo() {
return foo;
}
}
业务中,假设我们需要获取 Outer 对象对底层的 Inner 中的 foo 属性,我们必须写一堆的非空校验,来防止发生 NullPointerException:
// 繁琐的代码
Outer outer = new Outer();
if (outer != null && outer.nested != null && outer.nested.inner != null) {
System.out.println(outer.nested.inner.foo);
}
通过 Optional
在 Java8 中,我们有更优雅的解决方式,那就是使用 Optional是说,我们可以在一行代码中,进行流水式的 map 操作。而 map 方法内部会自动进行空校验:
Optional.of(new Outer())
.map(Outer::getNested)
.map(Nested::getInner)
.map(Inner::getFoo
.ifPresent(System.out::println); // 如果不为空,最终输出 foo 的值
通过 suppiler 函数自定义增强 API
上面这种方式个人感觉还是有点啰嗦,我们可以利用 suppiler 函数来出一个终极解决方案:
public static <T> Optional<T> resolve(Supplier<T> resolver) {
try {
T result = resolver.get();
return Optional.ofNullable(result);
}
catch (NullPointerException e) {
// 可能会抛出空指针异常,直接返回一个空的 Optional 对象
return Optional.empty();
}
}
利用上面的 resolve 方法来重构上述的非空校验代码段:
Outer obj = new Outer();
// 直接调用 resolve 方法,内部做空指针的处理
resolve(() -> obj.getNested().getInner().getFoo());
.ifPresent(System.out::println); // 如果不为空,最终输出 foo 的值
最后
你需要知道的是,上面这两个解决方案并没传统的 null 检查性能那么高效。但在绝大部分业务场景下,舍弃那么一丢丢的性能来方便编码,是完全可取,
除非是那种对性能有严格要求的场景,我们才不建议使用。
个人觉得,真要拿这点性能说事,还不如去优化优化 sql 语句,业务逻辑等。
GitHub 地址
https://github.com/weiwosuoai/java8_guide
Java8 新特性 | 如何风骚走位防止空指针异常的更多相关文章
- Java8新特性之空指针异常的克星Optional类
Java8新特性系列我们已经介绍了Stream.Lambda表达式.DateTime日期时间处理,最后以"NullPointerException" 的克星Optional类的讲解 ...
- 【Java8新特性】Optional类在处理空值判断场景的应用 回避空指针异常 编写健壮的应用程序
一.序言 空值异常是应用运行时常见的异常,传统方式为了编写健壮的应用,常常使用多层嵌套逻辑判断回避空指针异常.Java8新特性之Optional为此类问题提供了优雅的解决方式. 广大程序员朋友对空值异 ...
- java8新特性全面解析
在Java Code Geeks上有大量的关于Java 8 的教程了,像玩转Java 8--lambda与并发,Java 8 Date Time API 教程: LocalDateTime和在Java ...
- 这可能是史上最好的 Java8 新特性 Stream 流教程
本文翻译自 https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ 作者: @Winterbe 欢迎关注个人微信公众 ...
- 干货 | Java8 新特性教程
本教程翻译整理自 https://github.com/winterbe/java8-tutorial 本教程首发自个人网站: https://www.exception.site/java8/jav ...
- 乐字节-Java8新特性之Optional
上一篇小乐带大家了解了Java新特性之Stream,接下来将会继续述说Java新特性之Optional Optional<T>类(java.util.Optional)是一个容器类,代表一 ...
- java8新特性之Optional类
NullPointException可以说是所有java程序员都遇到过的一个异常,虽然java从设计之初就力图让程序员脱离指针的苦海,但是指针确实是实际存在的,而java设计者也只能是让指针在java ...
- Java8 新特性之Stream API
1. Stream 概述 Stream 是Java8中处理集合的关键抽象概念,可以对集合执行非常复杂的查找,过滤和映射数据等操作; 使用 Stream API 对集合数据进行操作,就类似于使用 SQL ...
- Java8新特性——StreamAPI(二)
1. 收集器简介 收集器用来将经过筛选.映射的流进行最后的整理,可以使得最后的结果以不同的形式展现. collect方法即为收集器,它接收Collector接口的实现作为具体收集器的收集方法. Col ...
随机推荐
- unity Tab键实现切换输入框功能
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; ...
- Vue项目预渲染机制引入实践
周末想顺便把已经做好静态页面的webApp项目做一下SEO优化,由于不想写蹩脚的SSR代码,所以准备采用预渲染,本来想着网上有这么多预渲染的文章,随便找个来跟着做不就完了嘛,结果年轻的我付出了整个周末 ...
- python: 列表的方法
操作 函数 使用方法 备注 索引 index in: example.index(‘creative’) --- 1 in:example[1,] --- [’creative’, [’京东’,996 ...
- Stream闪亮登场
Stream闪亮登场 一. Stream(流)是什么,干什么 Stream是一类用于替代对集合操作的工具类+Lambda式编程,他可以替代现有的遍历.过滤.求和.求最值.排序.转换等 二. Strea ...
- [POJ1961]Period (KMP)
题意 求字符串s的最小循环元长度和循环次数 思路 s[1~i]满足循环元要len能整除i并且s[len+1~i]=s[1~i-len] 代码 #include<cstdio> #inclu ...
- Bootstarp 使用布局
实现 Bootstrap 基本布局 看到了一篇 20 分钟打造 Bootstrap 站点的文章,内容有点老,重新使用 Bootstrap3 实现一下,将涉及的内容也尽可能详细说明. 1. 创建基本的页 ...
- ubuntu 14.04 安装 rabbitmq
1. sudo apt-get update 安装rabbitmq 2. sudo apt-get install rabbitmq-server 添加用户 3. sudo rabbitmqctl a ...
- pygame学习
http://eyehere.net/2011/python-pygame-novice-professional-3/ http://www.pygame.org/docs/ref/event.ht ...
- Android完全退出应用的方法
退出程序 public static void exitApp(Context context){ ActivityManager activityManager = (ActivityManager ...
- Android进程间通信IPC
一.IPC的说明 IPC是Inter-Process Communication的缩写,含义为进程间通信或跨进程通信,是指两个进程之间进行数据交换的过程. IPC不是Android独有的,任何一个操作 ...