java 14 新特性 友好的空指针异常

引入

NullPointerException是Java开发中经常会遇到的异常。在JDK 14之前的版本中,NullPointerException异常的消息只是简单的null,并不会告诉你任何有用的信息,只能根据异常产生的源文件的行号来查找。对于很长的引用链来说,很难定位到底是哪个对象为null。比如,类似a.b.c.d这样的引用方式,abc中的任何一个为null,都会出现NullPointerException异常。仅靠行号无法快速定位问题所在。

在下面的代码中,对p.address.go();的调用会出现NullPointerException异常。

public class Npe {
    public static void main(String[] args) {
        People p = new People();
        p.address.go();
    }
}

class People{
    Address address;
}

class Address{
    public void go(){
        System.out.println("我们出去旅游吧");
    }
}

直接运行该文件的错误信息如下所示,从中我们只可以知道错误出现在6行,但是并不清楚错误的具体对象是谁为null

Exception in thread "main" java.lang.NullPointerException
    at com.itheima.hello.Npe.main(Npe.java:6)

详解

JEP 358增强了对NullPointerException异常的处理,可以显示详细的信息。这个功能需要通过选项-XX:+ShowCodeDetailsInExceptionMessages启用,如下所示:

java -XX:+ShowCodeDetailsInExceptionMessages Npe

输出的信息如下所示。错误消息明确的指出了anull

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Address.go()" because "<local1>.address" is null
        at NpeDemo01.main(NpeDemo01.java:4)

其它情况示范

但是对于更复杂的代码,不使用调试器就无法确定哪个变量为空。假设下面的代码中出现了一个NPE:

a.b.c.i = 99;

仅仅使用文件名和行数,并不能精确定位到哪个变量为null,是a、b还是c?

访问数组也会发生类似的问题。假设此代码中出现一个NPE:

a[i][j][k] = 99;

文件名和行号不能精确指出哪个数组组件为空。是a还是a[i]a[i][j]

一行代码可能包含多个访问路径,每个访问路径都可能是NPE的来源。假设此代码中出现一个NPE:

a.i = b.j;

文件名和行号并不能确定哪个对象为空,是a还是b?

NPE也可能在方法调用中传递,看下面的代码:

x().y().i = 99;

文件名和行号不能指出哪个方法调用返回null。是x()还是y()?

详细示例

接下来我们来示范一下如下的情况下:a.i = b.j

public class NpeDemo01 {
    public static void main(String[] args) {
        A a = new A();
        B b =null;
        System.out.println(a.i == b.j);
    }
}

class A{
    int i;
}
class B{
    int j;
}

直接执行代码

java -XX:+ShowCodeDetailsInExceptionMessages NpeDemo01.java

异常信息

Exception in thread "main" java.lang.NullPointerException: Cannot read field "j" because "<local2>" is null        at NpeDemo01.main(NpeDemo01.java:5)
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容