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

How is NullPointerException in Java 14 different from its predecessor?

Java SE 14 引入的重要功能之一是 Helpful NullPointerExceptions,这与 NullPointerException.是什么让 Java SE 14 中的 NullPointerException 比其前身更有用?

JVM 在程序中试图取消引用 null 引用的地方抛出 NullPointerException。对于 Java SE 14,NullPointerException 提供有关程序提前终止的有用信息。 Java SE 14 之后,JVM 在 NullPointerException 中使用 空详细信息 描述变量(根据源代码)。通过更清晰地将动态异常与静态程序代码相关联,它极大地提高了程序理解。

我们可以通过一个例子看出不同。

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

A new option is available to provide more helpful NullPointerException messages:

-XX:+ShowCodeDetailsInExceptionMessages

If the option is set, on encountering a null pointer, the JVM analyzes the program to determine which reference was null and then provides the details as part of NullPointerException.getMessage(). In addition to the exception message, the method, filename, and line number are also returned.

By default, this option is disabled.

和完整的提案 JEP 358 用于激励。

最终

What's new in JDK 15

The default of the flag ShowCodeDetailsInExceptionMessages was changed to 'true'.

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

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

person.name = student.name;

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

java.lang.NullPointerException: Cannot read field "name" because "student" is null

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