如何在 Java8 中风骚走位避开空指针异常

探讨Java8中预防NullPointerException的技巧,介绍Optional类及Supplier函数优化空对象检查,提升代码优雅度。

前言

要说 Java 编程中哪个异常是你印象最深刻的,那 NullPointerException 空指针可以说是臭名昭著的。不要说初级程序员会碰到,即使是中级,专家级程序员稍不留神,就会掉入这个坑里。

Null 引用的发明者 Tony Hoare 曾在 2009 年作出道歉声明,声明中表示,到目前为止,空指针异常大约给企业已造成数十亿美元的损失。

事已至此,我们必须学会面对它。So, 我们要如何防止空指针异常呢?

唯一的办法就是对可能为 Null 的对象添加检查。但是 Null 检查是繁琐且痛苦的。所以一些比较新的语言为了处理 Null 检查,特意添加了特殊的语法,如空合并运算符。

在 Groovy 或 Kotlin 这样的语言中也被称为 Elvis 运算符。

不幸的是,在老版本的 Java 中并没有提供这样的语法糖。Java8 中在这方面做了改进。所以,这篇文章就特意来介绍一下如何在 Java8 中利用新特性来编写防止 NullPointerException的发生。

Java8 中如何加强对 Null 对象的检查?

在上篇文章 Java8 新特性指导手册 中简单的提了一下如何通过 Optional 类来对对象做空校验。接下来,我们再细说一下:

在业务系统中,对象中嵌套对象是经常发生的场景,如下示例代码:

1.	// 最外层对象
2.	class Outer {
3.	    Nested nested;
4.	    Nested getNested() {
5.	        return nested;
6.	    }
7.	}
8.	// 第二层对象
9.	class Nested {
10.	    Inner inner;
11.	    Inner getInner() {
12.	        return inner;
13.	    }
14.	}
15.	// 最底层对象
16.	class Inner {
17.	    String foo;
18.	    String getFoo() {
19.	        return foo;
20.	    }
21.	}

业务中,假设我们需要获取 Outer 对象对底层的 Inner 中的 foo 属性,我们必须写一堆的非空校验,来防止发生 NullPointerException

1.	// 繁琐的代码
2.	Outer outer = new Outer();
3.	if (outer != null && outer.nested != null && outer.nested.inner != null) {
4.	    System.out.println(outer.nested.inner.foo);
5.	}

1、通过 Optional

Java8 中,我们有更优雅的解决方式,那就是使用 Optional是说,我们可以在一行代码中,进行流水式的 map 操作。而 map 方法内部会自动进行空校验

1.	Optional.of(new Outer())
2.	    .map(Outer::getNested)
3.	    .map(Nested::getInner)
4.	    .map(Inner::getFoo
5.	    .ifPresent(System.out::println); // 如果不为空,最终输出 foo 的值

2、通过 suppiler 函数自定义方法

上面这种方式个人感觉还是有点啰嗦,我们可以利用 suppiler 函数来出一个终极解决方案:

1.	public static <T> Optional<T> resolve(Supplier<T> resolver) {
2.	    try {
3.	        T result = resolver.get();
4.	        return Optional.ofNullable(result);
5.	    }
6.	    catch (NullPointerException e) {
7.	        // 可能会抛出空指针异常,直接返回一个空的 Optional 对象
8.	        return Optional.empty();
9.	    }
10.	}

利用上面的 resolve 方法来重构上述的非空校验代码段:

1.	Outer obj = new Outer();
2.	// 直接调用 resolve 方法,内部做空指针的处理
3.	resolve(() -> obj.getNested().getInner().getFoo());
4.	    .ifPresent(System.out::println); // 如果不为空,最终输出 foo 的值

最后

你需要知道的是,上面这两个解决方案并没传统的 null 检查性能那么高效。但在绝大部分业务场景下,舍弃那么一丢丢的性能来方便编码,是完全可取,除非是那种对性能有严格要求的,我们才不建议使用。

个人觉得,真要拿这点性能说事,还不如去优化优化 sql 语句,业务逻辑等。

文自:如何在 Java8 中风骚走位避开空指针异常

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值