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

前言

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

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

下面是 Tony Hoare 的原话:

我将 Null 引用的设计称为是一个数十亿美元的错误。1965 那年,我正在用面向对象语言(ALGOL W) 设计首个功能全面的系统。当时我的考量是,确保所有被使用的引用都是安全的,编译器会自动进行检查。但是,我没有抵住诱惑,加入了 Null 引用,仅仅是为了实现起来省事。这之后,它导致了数不清的 bug、错误和系统崩溃,也为企业导致了不可估量的损失。

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

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

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

不幸的是,在老版本的 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 语句,业务逻辑等。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • java 避免出现NullPointerException(空指针)的方法总结

    java 避免出现NullPointerException(空指针)的方法总结 Java应用中抛出的空指针异常是解决空指针的最好方式,也是写出能顺利工作的健壮程序的关键.俗话说"预防胜于治疗",对于这么令人讨厌的空指针异常,这句话也是成立的.值得庆幸的是运用一些防御性的编码技巧,跟踪应用中多个部分之间的联系,你可以将Java中的空指针异常控制在一个很好的水平上.顺便说一句,这是Javarevisited上的第二个空指针异常的帖子.在上个帖子中我们讨论了Java中导致空指针异常的常见原因

  • 浅谈java异常处理之空指针异常

    听老师说,在以后的学习中大部分的异常都是空指针异常.所以抽点打游戏的时间来查询一下什么是空指针异常 一:空指针异常产生的主要原因如下: (1)当一个对象不存在时又调用其方法会产生异常obj.method() // obj对象不存在 (2)当访问或修改一个对象不存在的字段时会产生异常obj.method() // method方法不存在 (3)字符串变量未初始化: (4)接口类型的对象没有用具体的类初始化,比如: List lt:会报错 List lt = new ArrayList():则不会报

  • Java中避免空指针异常的方法

    没人会喜欢空指针异常!有什么方法可以避免它们吗?或许吧.. 本文将讨论到以下几种技术 1.Optional类型(Java 8中新引入的) 2.Objects类(Java 7中原有的) Java 8中的Optional类 它是什么? 1.Java 8中新引入的类型 2.它是作为某个指定类型的对象的包装器或者用于那些不存在对象(null)的场景 简单来说,它是处理空值的一个更好的替代品(警告:乍一看可能并没有那么明显) 基本用法 它是一种类型(一个类)--那么,怎么才能创建一个这个类型的实例? 使用

  • 利用Java8 Optional如何避免空指针异常详解

    前言 空指针是我们最常见也最讨厌的异常,为了防止空指针异常,你不得在代码里写大量的非空判断. Java 8引入了一个新的Optional类.用于避免空指针的出现,也无需在写大量的if(obj!=null)这样的判断了,前提是你得将数据用Optional装着,它就是一个包裹着对象的容器. 都说没有遇到过空指针异常的程序员不是Java程序员,null确实引发过很多问题.Java 8中引入了一个叫做java.util.Optional的新类可以避免null引起的诸多问题. 我们看看一个null引用能导

  • Java函数式开发 Optional空指针处理

    摘要 空闲时会抽空学习同在jvm上运行的Groovy和Scala,发现他们对null的处理比早期版本Java慎重很多.在Java8中,Optional为函数式编程的null处理给出了非常优雅的解决方案.本文将说明长久以来Java中对null的蹩脚处理,然后介绍使用Optional来实现Java函数式编程. 那些年困扰着我们的null 在Java江湖流传着这样一个传说:直到真正了解了空指针异常,才能算一名合格的Java开发人员.在我们逼格闪闪的java码字符生涯中,每天都会遇到各种null的处理,

  • 由@NotNull注解引出的关于Java空指针的控制

    Java 小技巧和在java应用避免NullPonintException的最佳方法 在java应用程序中,一个NullPonintException(空指针异常)是最好解决(问题)的方法.同时,空指针也是写健壮的顺畅运行的代码的关键."预防好过治疗"这句话也同样适用于令人不爽的NullPonintException.通过应用防御性的编码技术和在遵守多个部分之间的约定,你可以再很大程度上避免NullPointException.下面的这些java小技巧可以最小化像!=null这种检查的

  • java 代码中预防空指针异常的处理办法

    项目中遇到的NullPointerException 分两种情况: 1. 引用空对象,即调用空对象的方法或引用空对象的属性. 2. 将8中基础类型的封装类赋值给对应的基础类. 1.对于别人接口的返回对象要做非空判断,因为我们不清楚获得的对象会不会为空,对于Collection Map 我一般会调用CollectionUtils MapUtils ,对于返回的String对象,我会调StringUtils.isNotEmpty()进行非空判断.他们中isNotEmpty不仅判断了NULL 还判断了

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

    前言 要说 Java 编程中哪个异常是你印象最深刻的,那 NullPointerException 空指针可以说是臭名昭著的.不要说初级程序员会碰到, 即使是中级,专家级程序员稍不留神,就会掉入这个坑里. Null 引用的发明者Tony Hoare 曾在 2009 年作出道歉声明,声明中表示,到目前为止,空指针异常大约给企业已造成数十亿美元的损失. 下面是 Tony Hoare 的原话: 我将 Null 引用的设计称为是一个数十亿美元的错误.1965 那年,我正在用面向对象语言(ALGOL W)

  • Java8中Optional类型和Kotlin中可空类型的使用对比

    本文主要给大家介绍了关于Java8中Optional类型和Kotlin中可空类型使用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 在 Java 8中,我们可以使用 Optional 类型来表达可空的类型. package com.easy.kotlin; import java.util.Optional; import static java.lang.System.out; /** * Optional.ofNullable - 允许传递为 null 参数 *

  • Java8中的 Lambda表达式教程

     1. 什么是λ表达式 λ表达式本质上是一个匿名方法.让我们来看下面这个例子: public int add(int x, int y) { return x + y; } 转成λ表达式后是这个样子: (int x, int y) -> x + y; 参数类型也可以省略,Java编译器会根据上下文推断出来: (x, y) -> x + y; //返回两数之和 或者 (x, y) -> { return x + y; } //显式指明返回值 可见λ表达式有三部分组成:参数列表,箭头(-&g

  • Java8中lambda表达式的应用及一些泛型相关知识

    语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public class Employee { public String name; public int age; public char sex; public String time; public int salary; } 我们有一列此类数据 List<Employee> data = Arrays.asL

  • Java8中的lambda表达式入门教程

    1.基本介绍 lambda表达式,即带有参数的表达式,为了更清晰地理解lambda表达式,先上代码: 1.1 两种方式的对比 1.1.1 方式1-匿名内部类 class Student{ private String name; private Double score; public Student(String name, Double score) { this.name = name; this.score = score; } public String getName() { ret

  • 详解java8中的Stream数据流

    Stream是java8引入的一个重度使用lambda表达式的API.Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象.直观意味着开发者在写代码时只需关注他们想要的结果是什么而无需关注实现结果的具体方式.这一章节中,我们将介绍为什么我们需要一种新的数据处理API.Collection和Stream的不同之处以及如何将StreamAPI应用到我们的编码中. 筛选重复的元素 Stream 接口支持 distinct 的方法, 它会返回一个元素

  • 如何更好的使用Java8中方法引用详解

    前言 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法.方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文.计算时,方法引用会创建函数式接口的一个实例. 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些.方法引用是一种更简洁易懂的Lambda表达式. 注意:方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::". 在Java8中,使用方法引用非常简单,如String

  • java8中lamba表达式的使用

    (-1)前言 学习lamba表达式是十分重要的,你会发现java变的可爱多了. (0)函数式接口 只有一个方法的接口称为函数式接口 JButton jButton = new JButton("123"); jButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) {}}); 等同于 jButton.addActionListener(e-&

  • 浅谈java8中map的新方法--replace

    Map在Java8中新增了两个replace的方法 1.replace(k,v) 在指定的键已经存在并且有与之相关的映射值时才会将指定的键映射到指定的值(新值) 在指定的键不存在时,方法会return回来一个null javadoc的注释解释了该默认值方法的实现的等价Java代码: if (map.containsKey(key)) { return map.put(key, value); } else { return null; } 下面展示的是新方法和JDK8之前的方法比较: /* *

  • 初识Java8中的Stream

    lambda表达式是stream的基础,初学者建议先学习lambda表达式,http://www.jb51.net/article/121129.htm 1.初识stream 先来一个总纲: 东西就是这么多啦,stream是java8中加入的一个非常实用的功能,最初看时以为是io中的流(其实一点关系都没有),让我们先来看一个小例子感受一下: @Before public void init() { random = new Random(); stuList = new ArrayList<St

随机推荐