资讯专栏INFORMATION COLUMN

在 Java 8 中避免 Null 检查

ethernet / 689人阅读

摘要:在中避免检查原文译者来源在中避免检查如何预防中著名的异常这是每个初学者迟早会问到的关键问题之一。引用的发明者在年道歉,并称这种错误为他的十亿美元错误。但幸运的是这在中得到了改善。检查是在底层自动处理的。

在 Java 8 中避免 Null 检查

原文:Avoid Null Checks in Java 8

译者:ostatsu

来源:在 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  Optional resolve(Supplier resolver) {
    try {
        T result = resolver.get();
        return Optional.ofNullable(result);
    }
    catch (NullPointerException e) {
        return Optional.empty();
    }
}

请记住,这两个解决方案可能没有传统 null 检查那么高的性能。不过在大多数情况下不会有太大问题。

像往常一样,上面的示例代码都托管在 GitHub。

祝编码愉快!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64966.html

相关文章

  • 别再写 bug 了,避免空指针的 5 个案例!

    摘要:本文,栈长将带你了解什么是空指针,还有如何有效的避免空指针。如何避免空指针下面说几个空指针的几个最常见的案例及解决之道。字符串比较,常量放前面这个时候可能为造成空指针异常,应该把常量放前面,就能避免空指针异常。 空指针是我们 Java 开发人员经常遇到的一个基本异常,这是一个极其普遍但似乎又无法根治的问题。 本文,栈长将带你了解什么是空指针,还有如何有效的避免空指针。 什么是空指针? ...

    zzzmh 评论0 收藏0
  • Java8实战》-第十章笔记(用Optional取代null

    摘要:是第一批在堆上分配记录的类型语言之一。实际上,的这段话低估了过去五十年来数百万程序员为修复空引用所耗费的代价。很明显,这种方式不具备扩展性,同时还牺牲了代码的可读性。是目前程序开发中最典型的异常。完成这一任务有多种方法。 用Optional取代null 如果你作为Java程序员曾经遭遇过NullPointerException,请举起手。如果这是你最常遭遇的异常,请继续举手。非常可惜,...

    flybywind 评论0 收藏0
  • Java8新特性总览

    摘要:新特性总览标签本文主要介绍的新特性,包括表达式方法引用流默认方法组合式异步编程新的时间,等等各个方面。还有对应的和类型的函数连接字符串广义的归约汇总起始值,映射方法,二元结合二元结合。使用并行流时要注意避免共享可变状态。 Java8新特性总览 标签: java [TOC] 本文主要介绍 Java 8 的新特性,包括 Lambda 表达式、方法引用、流(Stream API)、默认方...

    mayaohua 评论0 收藏0
  • How to handle Null Pointer Exception(译)

    摘要:我们应该考虑使用字符串常量调用方法来代替使用对象调用该方法。然而如果我们通过字符串常量来调用方法,执行流程会正常进行检查方法的参数在执行方法的方法体之前,务必对方法的参数进行值检查。 原文地址作者 Sotirios-Efstathios (Stathis) Maneas译者 smallcloverThanks for your watching! java.lang.NullPoine...

    MRZYD 评论0 收藏0
  • [译] Java 最常见的 5 个错误

    摘要:近日,在上列举了开发中常见的个错误,与君共免。在多线程中并发修改集合内容是非常常见的,因此需要使用并发编程中常用的方法进行处理,例如同步锁对于并发修改采用特殊的集合等等。在单线程和多线程情况下解决这个问题有微小的差别。 在编程时,开发者经常会遭遇各式各样莫名错误。近日,Sushil Das 在 Geek On Java上列举了 Java 开发中常见的 5 个错误,与君共「免」。 原文...

    chemzqm 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<