Java中的 NullPointerException 是什么?该如何解决?

本文详细介绍了Java中的NullPointerException,包括基本类型和引用类型的差异,何时会触发NPE,以及如何通过初始化和使用Objects.requireNonNull避免此类错误。还讨论了Java14中新增的异常根因显示功能,帮助开发者更好地诊断问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java中有两种主要类型的变量:

  1. 基本类型:包含数据的变量。如果想要操作基本类型变量中的数据,可以直接操作该变量。按照惯例,基本数据类型以小写字母开头。例如,intchar类型的变量是基本数据类型。
  2. 引用:包含对象的内存地址的变量,即引用对象的变量。如果要操作引用变量所引用的对象,必须解引用它。解除引用通常需要使用。访问一个方法或字段,或使用索引一个数组。按照惯例,引用类型通常用大写字母开头的类型表示。例如,Object类型的变量是引用。

输入以下代码,其中你声明了一个基本类型为int的变量,但没有初始化它:

int x;

int y = x + x;

这两行将使程序崩溃,因为你没有为x指定值,而我们试图使用x的值来为y赋值。所有原语在被操作之前都必须初始化为一个可用的值。

现在事情变得有趣了。引用变量可以设置为null,这意味着我什么也不引用如以这种方式显式地设置引用变量,或者引用变量未初始化,编译器不会捕获它(Java将自动将该变量设置为空),则可以在引用变量中获得空值。

NullPointerException (NPE,Null Pointer Exception 的缩写)通常发生在声明一个变量,但在尝试使用变量的内容之前没有创建一个对象并将其赋值给该变量。所以你引用的东西实际上并不存在。

输入以下代码 :

Integer num;

num = new Integer(10);

第一行声明了一个名为num的变量,但它实际上还没有包含引用值。因为你还没有说要指向什么,所以Java将它设置为null。

在第二行中,new关键字用于实例化(或创建)Integer类型的对象,并将引用变量num分配给该Integer对象。

如果你试图在创建对象之前解引用num,你会得到一个NullPointerException。在最简单的情况下,编译器会发现问题并告诉你“num may not have been initialized”,但有时你可能会编写不直接创建对象的代码。

例如,你可能有如下方法:

public void doSomething(SomeObject obj) {

    //我们假设obj不是null

    obj.myMethod();

}

在这种情况下,你没有创建对象obj,而是假设它是在调用doSomething()方法之前创建的。注意,可以像这样调用方法:

doSomething(null);

在这种情况下,objnull,语句obj. mymethod()将抛出一个NullPointerException

如果该方法打算像上面的方法一样对传入的对象做一些事情,抛出NullPointerException是合适的,因为这是一个程序员错误,而程序员将需要该信息进行调试。

除了由于方法的逻辑而抛出的NullPointerException之外,你还可以通过在方法的开头附近添加如下内容来检查方法参数是否为空值并显式抛出NPEs:

  // 如果obj为空,抛出一个带有自定义错误消息的NPE

Objects.requireNonNull(obj, "obj  不能为 Null");

注意,在错误消息中清楚地说明哪个对象不能为null是很有帮助的。验证这一点的好处是:

1)你可以返回更清楚的错误消息;

2)对于方法的其余部分,你知道除非obj被重新分配,否则它不是空的,可以安全地解引用。

或者,在有些情况下,方法的目的不仅仅是操作传入的对象,因此空形参可能是可以接受的。在这种情况下,你需要检查空参数并采取不同的行为。你还应该在文档中解释这一点。例如,doSomething()可以写成:

  /**

   * @param 可选 foo,可能为 null,那么结果也是 null

   */

  public void doSomething(SomeObject obj) {

    if (obj == null) {

      // …

    } else {

      // …

    }

  }

那么如何使用堆栈跟踪定位异常和原因

在Java 14中添加了一个新的语言特性来显示NullPointerException的根本原因。该语言特性自2006年以来一直是SAP商业JVM的一部分。在Java中14。下面是一个示例NullPointerException异常消息:

    in thread "main" java.lang.NullPointerException: Cannot invoke "java.util.List.size()" because "list" is null

    导致NullPointerException发生的情况列表

    以下是Java语言规范中直接提到的NullPointerException发生的所有情况:

(1)访问(即获取或设置)空引用的实例字段。(静态字段不列入其中)

(2)调用空引用的实例方法。(静态字段不列入其中)

(3)throw null;

(4)访问空数组的元素。

(5)同步为空 - synchronized (someNullReference) { ... }

(6)如果它的一个操作数是空引用,任何整数/浮点运算符都可以抛出NullPointerException

(7)如果装箱的值为空,则开箱转换抛出NullPointerException

(8)在空引用上调用super会抛出NullPointerException异常

    package com.莱迪娜的风声;

class Outer {

    class Inner {}

}

class ChildOfInner extends Outer.Inner {

    ChildOfInner(Outer o) {

        o.super(); // 如果 o null, 将会抛出NPE

    }

}

9)使用for (element: iterable)循环遍历空集合/数组。

10switch (foo) { ... } foo为空时 (无论是表达式还是语句) 会抛出一个NullPointerException.

11foo.new SomeInnerClass() foo为空时 会抛出NullPointerException.

12name1::name2primaryExpression:: name的方法引用在name1::name2primaryExpression求值为空时将会抛出NullPointerException

someInstance.someStaticMethod()不会抛出NPE,因为someStaticMethod是静态的,但someInstance::someStaticMethod仍然抛出NPE!

以上是关于 Java中的 NullPointerException 的介绍,以及在何种情况下会抛出空指针异常的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莱迪娜的风声

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值