Java 14 中的 NullPointerException 与其前身有何不同?

问题描述

Java SE 14 引入的一项重要功能Helpful NullPointerExceptions,它与 NullPointerException 的可用性有关。是什么让 Java SE 14 中的 NullPointerException 比其前身更有用?

解决方法

JVM 在程序中的代码试图取消引用 NullPointerException 引用的位置抛出一个 null。在 Java SE 14 中,NullPointerException 提供了有关程序提前终止的有用信息。从 Java SE 14 开始,JVM 在 NullPointerException 中使用 null-detail 消息来描述变量(根据源代码)。通过更清晰地将动态异常与静态程序代码关联起来,大大提高了程序理解能力。

让我们通过一个例子来看看区别。

import java.util.ArrayList;
import java.util.List;

class Price {
    double basePrice;
    double tax;

    public Price() {
    }

    public Price(double basePrice) {
        this.basePrice = basePrice;
    }

    public Price(double basePrice,double tax) {
        this.basePrice = basePrice;
        this.tax = tax;
    }
    // ...
}

class Product {
    String name;
    Price price;

    public Product() {
    }

    public Product(String name,Price price) {
        this.name = name;
        this.price = price;
    }
    // ...
}

class CartEntry {
    Product product;
    int quantity;

    public CartEntry() {
    }

    public CartEntry(Product product,int quantity) {
        this.product = product;
        this.quantity = quantity;
    }

    // ...
}

class Cart {
    String id;
    List<CartEntry> cartEntries;

    public Cart() {
        cartEntries = new ArrayList<>();
    }

    public Cart(String id) {
        this();
        this.id = id;
    }

    void addToCart(CartEntry entry) {
        cartEntries.add(entry);
    }
    // ...
}

public class Main {
    public static void main(String[] args) {
        Cart cart = new Cart("XYZ123");
        cart.addToCart(new CartEntry());
        System.out.println(cart.cartEntries.get(0).product.price.basePrice);
    }
}

Java SE 14 之前的输出:

Exception in thread "main" java.lang.NullPointerException
    at Main.main(Main.java:74)

这条消息让程序员对 NullPointerException 的来源一无所知。

Java SE 14 以上的输出:

Exception in thread "main" java.lang.NullPointerException: Cannot read field "price" because "java.util.List.get(int).product" is null
    at Main.main(Main.java:74)

Java SE 14 中的 NullPointerException 还告诉我们哪个引用是 null

很大的改进!

,

它记录在发行说明中。

默认情况下,1.14 版中不显示新消息:

What's new in JDK 14

一个新选项可用于提供更有用的 NullPointerException 消息:

-XX:+ShowCodeDetailsInExceptionMessages

如果设置了该选项,则在遇到空指针时,JVM 会分析程序以确定哪个引用为空,然后将详细信息作为 NullPointerException.getMessage() 的一部分提供。除了异常信息外,还会返回方法、文件名和行号。

默认情况下,此选项处于禁用状态。

以及用于激励的完整提案 JEP 358

最终

What's new in JDK 15

标志 ShowCodeDetailsInExceptionMessages 的默认值已更改为“true”。

,

当 JVM 抛出 NullPointerException 时,它现在会添加一条详细消息,指定哪个引用为空。

这使得堆栈跟踪更易于解释,并在程序访问源代码中同一行上的多个引用时解决歧义。例如,线

person.name = student.name;

如果 NullPointerExceptionpersonstudent,则抛出 null,但在 Java 14 之前,异常并没有告诉我们它是哪一个。现在,它确实:

java.lang.NullPointerException: 无法读取字段“name”,因为“student”为空

有关此更改的更多信息,请参见 JEP-358