Java 简明教程

Java - Null Pointer Exception

在 Java 14 中,引入了一个新功能,称为 NullPointerException,它非常有用。当时这只是一个预览功能,后来成为了 JDK 的标准部分。这种增强的动机是使用更多详细信息丰富 NullPointerException,因为传统的 NullPointerException 只提供了文件名称、方法和发生 NullPointerException 的行号的详细信息。

Traditional Null Pointer Exception in Java

在 Java 14 NullPointerException 增强之前,以下代码将显示一条如下所示的 NullPointerException 消息:

// Create an employee without department
Employee emp = new Employee(1,"Robert",null);

// get the name of the dept
// as name is null, this code will throw a null pointer exception
String dept = emp.getDept().getName();

如果使用此代码片段进行运行,将生成类似的结果 −

Exception in thread "main" java.lang.NullPointerException
	at com.tutorialspoint.Tester.main(Tester.java:10)

New Informative Null Pointer Exception in Java

在调试过程中,此类错误消息没有用处。并且随着嵌套级别增加,检查哪个字段为 null 导致了此问题变得更加困难。Java 14 满足了此需求。在这样的情况下,它提供了一个选项,以返回以下更友好的消息:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.tutorialspoint.Department.getName()" because the return value of "com.tutorialspoint.Employee.getDept()" is null
	at com.tutorialspoint.Tester.main(Tester.java:10)

在这里我们可以看到,正在打印更友好的信息消息来帮助调试 getDept() 为 null 的问题。为了在 Java 14 中启用此功能,我们必须使用以下标志来运行 java 代码。

-XX:+ShowCodeDetailsInExceptionMessages

现在使用 Java 20,不再需要此标志。

Helpful NullPointerException for Null Objects

在这个示例中,我们展示了以上学习到的概念。它是一个很有用的特性,用于调试由 null 引用导致的问题。在这里,我们创建了两个类 Employee 和 Department。在 main 方法中,我们创建了 Employee 类的对象,但是将 department 传递为 null。然后,我们尝试获取员工的部门名称,这会产生 NullPointerException。在输出中,我们可以看到 JVM 引发的信息丰富的空指针异常。

Example

package com.tutorialspoint;

import java.util.List;

public class Tester {

   public static void main(String[] args) {
      // declare an employee without department
      Employee emp = new Employee(1,"Robert",null);

      // get department name of null department will
      // throw a NullPointerException
      String dept = emp.getDept().getName();
      System.out.println(dept);
   }
}

class Employee {
   int id;
   String name;
   Department dept;

   Employee (int id, String name, Department dept){
      this.id = id;
      this.name = name;
      this.dept = dept;
   }
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public Department getDept() {
      return dept;
   }
   public void setDept(Department dept) {
      this.dept = dept;
   }
}

class Department {
   int id;
   String name;
   List<Employee> employees;
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public List<Employee> getEmployees() {
      return employees;
   }
   public void setEmployees(List<Employee> employees) {
      this.employees = employees;
   }
}

Output

让我们编译并运行上述程序,这将生成以下结果 −

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.tutorialspoint.Department.getName()" because the return value of "com.tutorialspoint.Employee.getDept()" is null
	at com.tutorialspoint.Tester.main(Tester.java:10)

Informative NullPointerException - Local Null Variable

与对象引用类似,局部 variable 可能为 null。在 Java 14 中,如果使用了 null 局部变量,那么 JVM 会打印变量的名称为 <local>,如下所示:

String name = null;
System.out.println("Length: " + name.length() );

如果使用此代码片段进行运行,将生成类似的结果 −

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "<local1>" is null
	at com.tutorialspoint.Tester.main(Tester.java:8)

为了打印局部变量的名称,我们在运行程序时必须使用以下标志。

-g

使用此标志会产生以下输出。

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null
	at com.tutorialspoint.Tester.main(Tester.java:8)

在 Java 20 及更高版本中,不再需要此标志。请参见以下完整示例:

Helpful NullPointerException for Null Local Variable

在这个示例中,我们展示了以上学习到的概念,以调试 null 局部引用。在这里,我们创建了一个局部变量 name,并且尝试获取 null string 变量的长度,这会导致 NullPointerException。在输出中,我们可以看到 JVM 引发的带有 null 变量实际名称的信息丰富的空指针异常。

Example

package com.tutorialspoint;

public class Tester {

   public static void main(String[] args) {
	   String name = null;
       // accessing property of null local variable
       // will cause a NullPointerException
	   System.out.println("Length: " + name.length() );
   }
}

Output

让我们编译并运行上述程序,这将生成以下结果 −

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null
	at com.tutorialspoint.Tester.main(Tester.java:8)