什么是 NullPointerException,如何修复它?

发布于 2025-01-18 12:30:53 字数 116 浏览 3 评论 0 原文

什么是空指针异常 (java.lang.NullPointerException) 以及导致它们的原因是什么?

可以使用哪些方法/工具来确定原因,以便阻止异常导致程序提前终止?

What are Null Pointer Exceptions (java.lang.NullPointerException) and what causes them?

What methods/tools can be used to determine the cause so that you stop the exception from causing the program to terminate prematurely?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

提笔书几行 2025-01-25 12:30:53

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

  1. 基元:包含数据的变量。如果您想操作原始变量中的数据,您可以直接操作该变量。按照惯例,原始类型以小写字母开头。例如,intchar 类型的变量是基元。

  2. 引用:包含对象内存地址的变量,即引用对象的变量。如果您想要操作引用变量引用的Object,则必须取消引用它。取消引用通常需要使用 . 访问方法或字段,或使用 [ 索引数组。按照惯例,引用类型通常用以大写字母开头的类型来表示。例如,Object 类型的变量是引用。

考虑下面的代码,您声明了 primitive 类型 int 的变量并且不初始化它:

int x;
int y = x + x;

这两行将使程序崩溃,因为没有为 指定值x,我们尝试使用 x 的值来指定 y。所有基元在被操作之前都必须初始化为可用值。

现在事情变得有趣了。 引用变量可以设置为null,这意味着“我没有引用任何东西”。如果您以这种方式显式设置引用变量,则可以在引用变量中获取 null 值,或者引用变量未初始化并且编译器不会捕获它(Java 会自动将该变量设置为 null )。

如果您显式或通过 Java 自动将引用变量设置为 null,并且您尝试取消引用它,则会出现 NullPointerException

当您声明变量但在尝试使用变量的内容之前没有创建对象并将其分配给该变量时,通常会发生 NullPointerException (NPE)。所以你引用了一些实际上并不存在的东西。

如下代码:

Integer num;
num = new Integer(10);

第一行声明了一个名为num的变量,但它实际上还不包含引用值。由于您还没有说出要指向什么,Java 将其设置为 null

第二行,使用new关键字实例化(或创建)一个Integer类型的对象,并赋值引用变量num到该 Integer 对象。

如果您在创建对象之前尝试取消引用 num,您将收到 NullPointerException。在最简单的情况下,编译器会捕获问题并让您知道“num 可能尚未初始化”,但有时您可能会编写不直接创建对象的代码。

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

public void doSomething(SomeObject obj) {
   // Do something to obj, assumes obj is not null
   obj.myMethod();
}

在这种情况下,您不会创建对象 obj,而是假设它是在 doSomething() 方法之前创建的被称为。请注意,可以像这样调用该方法:

doSomething(null);

在这种情况下,objnull,并且语句 obj.myMethod() 将抛出 NullPointerException 。

如果该方法打算像上面的方法那样对传入的对象执行某些操作,则抛出 NullPointerException 是适当的,因为这是程序员错误,并且程序员需要该信息来进行调试。

除了由于方法逻辑引发的 NullPointerException 之外,您还可以检查方法参数中是否有 null 值,并通过在方法的开头:

// Throws an NPE with a custom error message if obj is null
Objects.requireNonNull(obj, "obj must not be null");

请注意,在错误消息中明确说明哪个对象不能为null会很有帮助。验证这一点的优点是 1) 您可以返回自己更清晰的错误消息,2) 对于方法的其余部分,您知道除非重新分配 obj ,否则它不为 null 并且可以安全地取消引用。

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

/**
  * @param obj An optional foo for ____. May be null, in which case
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj == null) {
       // Do something
    } else {
       // Do something else
    }
}

最后,如何查明异常&使用堆栈跟踪的原因

可以使用哪些方法/工具来确定原因,以便您停止
导致程序提前终止的异常?

具有 find bug 功能的声纳可以检测 NPE。
sonar能否动态捕获JVM引起的空指针异常

现在 Java 14 添加了一个新的语言功能来显示 NullPointerException 的根本原因。自 2006 年以来,此语言功能已成为 SAP 商业 JVM 的一部分。

在 Java 14 中,以下是 NullPointerException 异常消息示例:

在线程“main”中java.lang.NullPointerException:无法调用“java.util.List.size()”,因为“list”为空

导致 NullPointerException 发生的情况列表

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

  • 访问(即获取或设置)空引用的实例字段。 (静态字段不算数!)
  • 调用空引用的实例方法。 (静态方法不算数!)
  • throw null;
  • 访问 null 数组的元素。
  • 空值同步 - synchronized (someNullReference) { ... }
  • 如果任何整数/浮点运算符的操作数之一是装箱空引用,则任何整数/浮点运算符都可以抛出 NullPointerException
  • 拆箱转换如果装箱值为 null,则抛出 NullPointerException。
  • 对 null 引用调用 super 会引发 NullPointerException。如果您感到困惑,这里讨论的是合格的超类构造函数调用:
class Outer {
    class Inner {}
}
class ChildOfInner extends Outer.Inner {
    ChildOfInner(Outer o) { 
        o.super(); // if o is null, NPE gets thrown
    }
}
  • 使用 for (element : iterable) 循环来循环访问 null 集合/数组。

  • foo 为 null 时,

    switch (foo) { ... }(无论是表达式还是语句)可以抛出 NullPointerException

  • foo 为 null 时,

    foo.new SomeInnerClass() 抛出 NullPointerException

  • name1::name2primaryExpression::name 形式的方法引用在 name1 计算时抛出 NullPointerException code> 或 primaryExpression 计算结果为 null。

    来自 JLS 的注释指出,someInstance.someStaticMethod() 不会抛出 NPE,因为 someStaticMethod 是静态的,但 someInstance:: someStaticMethod 仍然抛出 NPE!

* 请注意,JLS 可能还间接谈论了很多有关 NPE 的内容。

There are two overarching types of variables in Java:

  1. Primitives: variables that contain data. If you want to manipulate the data in a primitive variable you can manipulate that variable directly. By convention primitive types start with a lowercase letter. For example variables of type int or char are primitives.

  2. References: variables that contain the memory address of an Object i.e. variables that refer to an Object. If you want to manipulate the Object that a reference variable refers to you must dereference it. Dereferencing usually entails using . to access a method or field, or using [ to index an array. By convention reference types are usually denoted with a type that starts in uppercase. For example variables of type Object are references.

Consider the following code where you declare a variable of primitive type int and don't initialize it:

int x;
int y = x + x;

These two lines will crash the program because no value is specified for x and we are trying to use x's value to specify y. All primitives have to be initialized to a usable value before they are manipulated.

Now here is where things get interesting. Reference variables can be set to null which means "I am referencing nothing". You can get a null value in a reference variable if you explicitly set it that way, or a reference variable is uninitialized and the compiler does not catch it (Java will automatically set the variable to null).

If a reference variable is set to null either explicitly by you or through Java automatically, and you attempt to dereference it you get a NullPointerException.

The NullPointerException (NPE) typically occurs when you declare a variable but did not create an object and assign it to the variable before trying to use the contents of the variable. So you have a reference to something that does not actually exist.

Take the following code:

Integer num;
num = new Integer(10);

The first line declares a variable named num, but it does not actually contain a reference value yet. Since you have not yet said what to point to, Java sets it to null.

In the second line, the new keyword is used to instantiate (or create) an object of type Integer, and the reference variable num is assigned to that Integer object.

If you attempt to dereference num before creating the object you get a NullPointerException. In the most trivial cases, the compiler will catch the problem and let you know that "num may not have been initialized," but sometimes you may write code that does not directly create the object.

For instance, you may have a method as follows:

public void doSomething(SomeObject obj) {
   // Do something to obj, assumes obj is not null
   obj.myMethod();
}

In which case, you are not creating the object obj, but rather assuming that it was created before the doSomething() method was called. Note, it is possible to call the method like this:

doSomething(null);

In which case, obj is null, and the statement obj.myMethod() will throw a NullPointerException.

If the method is intended to do something to the passed-in object as the above method does, it is appropriate to throw the NullPointerException because it's a programmer error and the programmer will need that information for debugging purposes.

In addition to NullPointerExceptions thrown as a result of the method's logic, you can also check the method arguments for null values and throw NPEs explicitly by adding something like the following near the beginning of a method:

// Throws an NPE with a custom error message if obj is null
Objects.requireNonNull(obj, "obj must not be null");

Note that it's helpful to say in your error message clearly which object cannot be null. The advantage of validating this is that 1) you can return your own clearer error messages and 2) for the rest of the method you know that unless obj is reassigned, it is not null and can be dereferenced safely.

Alternatively, there may be cases where the purpose of the method is not solely to operate on the passed in object, and therefore a null parameter may be acceptable. In this case, you would need to check for a null parameter and behave differently. You should also explain this in the documentation. For example, doSomething() could be written as:

/**
  * @param obj An optional foo for ____. May be null, in which case
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj == null) {
       // Do something
    } else {
       // Do something else
    }
}

Finally, How to pinpoint the exception & cause using Stack Trace

What methods/tools can be used to determine the cause so that you stop
the exception from causing the program to terminate prematurely?

Sonar with find bugs can detect NPE.
Can sonar catch null pointer exceptions caused by JVM Dynamically

Now Java 14 has added a new language feature to show the root cause of NullPointerException. This language feature has been part of SAP commercial JVM since 2006.

In Java 14, the following is a sample NullPointerException Exception message:

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

List of situations that cause a NullPointerException to occur

Here are all the situations in which a NullPointerException occurs, that are directly* mentioned by the Java Language Specification:

  • Accessing (i.e. getting or setting) an instance field of a null reference. (static fields don't count!)
  • Calling an instance method of a null reference. (static methods don't count!)
  • throw null;
  • Accessing elements of a null array.
  • Synchronising on null - synchronized (someNullReference) { ... }
  • Any integer/floating point operator can throw a NullPointerException if one of its operands is a boxed null reference
  • An unboxing conversion throws a NullPointerException if the boxed value is null.
  • Calling super on a null reference throws a NullPointerException. If you are confused, this is talking about qualified superclass constructor invocations:
class Outer {
    class Inner {}
}
class ChildOfInner extends Outer.Inner {
    ChildOfInner(Outer o) { 
        o.super(); // if o is null, NPE gets thrown
    }
}
  • Using a for (element : iterable) loop to loop through a null collection/array.

  • switch (foo) { ... } (whether its an expression or statement) can throw a NullPointerException when foo is null.

  • foo.new SomeInnerClass() throws a NullPointerException when foo is null.

  • Method references of the form name1::name2 or primaryExpression::name throws a NullPointerException when evaluated when name1 or primaryExpression evaluates to null.

    a note from the JLS here says that, someInstance.someStaticMethod() doesn't throw an NPE, because someStaticMethod is static, but someInstance::someStaticMethod still throw an NPE!

* Note that the JLS probably also says a lot about NPEs indirectly.

你没皮卡萌 2025-01-25 12:30:53

NullPointerException 是当您尝试使用指向内存中任何位置 (null) 的引用(就像引用对象一样)时发生的异常。对空引用调用方法或尝试访问空引用的字段将触发 NullPointerException。这些是最常见的,但 中列出了其他方法NullPointerException javadoc 页面。

我能想到的用于说明 NullPointerException 的最快示例代码可能是:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

main 内的第一行,我显式设置了 Object code> 引用 obj 等于 null。这意味着我有一个引用,但它没有指向任何对象。之后,我尝试通过调用该引用的方法来将该引用视为指向一个对象。这会导致 NullPointerException,因为在引用指向的位置没有要执行的代码。

(这是一个技术细节,但我认为值得一提的是:指向 null 的引用与指向无效内存位置的 C 指针不同。空指针实际上不指向任何地方,这与指向恰好无效的位置有细微的不同。)

NullPointerExceptions are exceptions that occur when you try to use a reference that points to no location in memory (null) as though it were referencing an object. Calling a method on a null reference or trying to access a field of a null reference will trigger a NullPointerException. These are the most common, but other ways are listed on the NullPointerException javadoc page.

Probably the quickest example code I could come up with to illustrate a NullPointerException would be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

On the first line inside main, I'm explicitly setting the Object reference obj equal to null. This means I have a reference, but it isn't pointing to any object. After that, I try to treat the reference as though it points to an object by calling a method on it. This results in a NullPointerException because there is no code to execute in the location that the reference is pointing.

(This is a technicality, but I think it bears mentioning: A reference that points to null isn't the same as a C pointer that points to an invalid memory location. A null pointer is literally not pointing anywhere, which is subtly different than pointing to a location that happens to be invalid.)

抠脚大汉 2025-01-25 12:30:53

什么是NullPoInterException?

一个好的起点是 javadocs 。他们涵盖了这一点:

在应用程序尝试使用null的情况下,在
需要对象。这些包括:

  • 调用空对象的实例方法。
  • 访问或修改空对象的字段。
  • 将零的长度占用,好像是一个数组。
  • 访问或修改null的插槽,就好像是数组一样。
  • 将无效的扔掉,好像是可抛价的价值。

应用程序应抛出此类的实例以指示其他
空对象的非法用途。

也是这样的情况,如果您尝试使用同步的null引用,也会引发此例外, per jls

 同步statement:
    同步(表达式)块
 
  • 否则,如果表达式的值为null,则抛出 nullpoInterException

我该如何修复?

因此,您有一个 nullpoInterException 。您如何修复它?让我们以一个简单的示例,该示例将 NullPoInterException

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

识别零值

第一步是确切地识别哪些值导致异常。为此,我们需要进行一些调试。学会阅读 stacktrace 很重要。这将向您展示抛出异常的位置:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

在这里,我们看到例外是在第13行上抛出的(在 printString 方法中)。查看该行并检查哪些值为null
添加记录语句或使用 debugger 。我们发现 s 是空的,并且在其上调用长度方法会引发异常。我们可以看到,当从该方法中删除 s.length()时,程序停止抛出异常。

跟踪这些值来自

下一步检查此值的来源。通过遵循该方法的呼叫者,我们看到 s printString(name)中传递给 print()方法和<代码> this.name 为null。

跟踪应设置这些值的位置

this.name 设置在哪里?在 setName(string)方法中。有了更多的调试,我们可以看到这种方法根本没有调用。如果调用了该方法,请确保检查顺序是否调用了这些方法,并且在打印方法之后未称为

这足以为我们提供一个解决方案:在调用 printer.setName()之前将调用添加到调用 printer.print()之前。

其他修复程序

该变量可以具有默认值(和 setName 可以防止其设置为null):

private String name = "";

print printsring 方法

printString((name == null) ? "" : name);

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

另请参见:

如果您尝试调试问题并且仍然没有解决方案,我仍然找不到问题

,您可以将问题发布更多帮助,但请确保包括到目前为止尝试的内容。至少,在问题中包含stacktrace 在代码中标记重要的线号。另外,请尝试首先简化代码(请参阅 sscce )。

What is a NullPointerException?

A good place to start is the JavaDocs. They have this covered:

Thrown when an application attempts to use null in a case where an
object is required. These include:

  • Calling the instance method of a null object.
  • Accessing or modifying the field of a null object.
  • Taking the length of null as if it were an array.
  • Accessing or modifying the slots of null as if it were an array.
  • Throwing null as if it were a Throwable value.

Applications should throw instances of this class to indicate other
illegal uses of the null object.

It is also the case that if you attempt to use a null reference with synchronized, that will also throw this exception, per the JLS:

SynchronizedStatement:
    synchronized ( Expression ) Block
  • Otherwise, if the value of the Expression is null, a NullPointerException is thrown.

How do I fix it?

So you have a NullPointerException. How do you fix it? Let's take a simple example which throws a NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Identify the null values

The first step is identifying exactly which values are causing the exception. For this, we need to do some debugging. It's important to learn to read a stacktrace. This will show you where the exception was thrown:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Here, we see that the exception is thrown on line 13 (in the printString method). Look at the line and check which values are null by
adding logging statements or using a debugger. We find out that s is null, and calling the length method on it throws the exception. We can see that the program stops throwing the exception when s.length() is removed from the method.

Trace where these values come from

Next check where this value comes from. By following the callers of the method, we see that s is passed in with printString(name) in the print() method, and this.name is null.

Trace where these values should be set

Where is this.name set? In the setName(String) method. With some more debugging, we can see that this method isn't called at all. If the method was called, make sure to check the order that these methods are called, and the set method isn't called after the print method.

This is enough to give us a solution: add a call to printer.setName() before calling printer.print().

Other fixes

The variable can have a default value (and setName can prevent it being set to null):

private String name = "";

Either the print or printString method can check for null, for example:

printString((name == null) ? "" : name);

Or you can design the class so that name always has a non-null value:

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

See also:

I still can't find the problem

If you tried to debug the problem and still don't have a solution, you can post a question for more help, but make sure to include what you've tried so far. At a minimum, include the stacktrace in the question, and mark the important line numbers in the code. Also, try simplifying the code first (see SSCCE).

沒落の蓅哖 2025-01-25 12:30:53

问题:是什么原因导致 NullPoInterException (NPE)?

如您所知,Java类型被分为原始类型 boolean int 等)和参考类型。 Java中的参考类型允许您使用特殊值 null ,这是Java说“无对象”的方法。

NullPoInterException 每当您的程序尝试使用 null 时,就会在运行时抛出,就像它是真正的参考。例如,如果您写下来:

public class Test {
    public static void main(String[] args) {
        String foo = null;
        int length = foo.length();   // HERE
    }
}

标记为“此处”的语句将尝试在 length()方法上运行 null 参考,这将抛出<代码> NullPoInterException 。

您可以使用许多方法使用 null 值,该值将导致 nullpoInterException 。实际上,您可以使用 null 而不会导致NPE的唯一事情是:

  • 将其分配给参考变量或从参考变量中读取它,
  • 将其分配给数组元素或从数组元素读取它(规定数组引用本身是非null!),
  • 将其作为参数传递或将其返回,或
  • 使用 == != 运算符,或实例

问题:如何阅读NPE StackTrace?

假设我编译并运行上面的程序:

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:4)
$

第一个观察:汇编成功!程序中的问题不是汇编错误。这是一个运行时错误。 (某些IDE可能会警告您的程序总是会抛出异常...但是标准 Javac 编译器不会。)

第二个观察:当我运行程序时,它输出了两行,“ Gobbledy-Gook ”。 错误!这是一个堆叠式...它提供重要信息,如果您花时间仔细阅读,它将帮助您跟踪代码中的错误。

因此,让我们看一下它说的内容:

Exception in thread "main" java.lang.NullPointerException

堆栈跟踪的第一行告诉您许多事情:

  • 它告诉您抛出异常的Java线程的名称。对于一个带有一个线程的简单程序(像这样),它将是“主”。让我们继续前进...
  • 它告诉您被抛出的例外的全名;即 java.lang.nullpointerexception
  • 如果异常具有关联的错误消息,则将在异常名称之后输出。 NullPoInterException 在这方面是不寻常的,因为它很少有错误消息。

第二行是诊断NPE的最重要的一条线。

at Test.main(Test.java:4)

这告诉我们许多事情:

  • “在test.main”中说我们在 main test 类的方法中。
  • “ test.java:4”给出了类的源文件名,它告诉我们,此次发生的说明是在文件的第4行中。

如果您计算上面文件中的行,则第4行是我标记为“此处”注释的行。

请注意,在一个更复杂的示例中,NPE堆栈跟踪中将有很多行。但是,您可以确定第二行(第一行)将告诉您NPE被抛出 1

简而言之,堆栈跟踪会明确地告诉我们该程序的哪种陈述已抛出了NPE。

另请参阅:什么是堆栈跟踪,我该如何使用它来调试应用程序错误?

1-1-1-1-1-1-不太正确。有一些称为嵌套异常的东西...

问题:如何跟踪代码中NPE异常的原因?

这是困难的部分。简短的答案是将逻辑推断应用于堆栈跟踪,源代码和相关API文档的证据。

让我们先用简单的示例(上)说明。我们首先要查看堆栈跟踪告诉我们的线路是NPE发生的位置:

int length = foo.length(); // HERE

如何抛出NPE?

实际上,只有一种方法:仅当 foo 具有值 null 时,才能发生。然后,我们尝试在 length()方法上运行 null 和... bang!

但是(我听到您说)如果NPE被扔进 length()方法调用中怎么办?

好吧,如果发生这种情况,堆栈跟踪看起来会有所不同。第一个“ at”行会说, java.lang.string 类和 test.java 的第4行中的某个行中的例外是第二个”。在“线”。

那么 null 从何而来?在这种情况下,这很明显,很明显,我们需要采取的措施来修复它。 (将非null值分配给 foo 。)

好的,让我们尝试一个更棘手的示例。这将需要一些逻辑扣除。

public class Test {

    private static String[] foo = new String[2];

    private static int test(String[] bar, int pos) {
        return bar[pos].length();
    }

    public static void main(String[] args) {
        int length = test(foo, 1);
    }
}

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.test(Test.java:6)
    at Test.main(Test.java:10)
$ 

因此,现在我们有两个“ AT”行。第一个是为了这条线:

return args[pos].length();

第二个是为此行的:

int length = test(foo, 1);
    

看第一行,那怎么会抛出NPE?有两种方法:

  • 如果 bar的值 null ,则 bar [pos] 将抛出NPE。
  • 如果 bar [pos] 的值是 null ,则调用 length()将抛出NPE。

接下来,我们需要弄清楚哪些情况解释了实际发生的情况。我们将从探索第一个开始:

bar 从哪里?它是 test 方法调用的参数,如果我们查看 test 的调用,我们可以看到它来自 foo 静态变量。此外,我们可以清楚地看到,我们将 foo 初始化为非零值。这足以暂时驳斥这一解释。 (从理论上讲,其他可能会更改 foo to null ...但这不是在这里发生的。)

那么我们的第二种情况呢?好吧,我们可以看到 pos 1 ,因此这意味着 foo [1] 必须为 null 。这可能吗?

确实是!这就是问题。当我们这样初始化时:

private static String[] foo = new String[2];

我们将 String [] 用两个元素分配给 null 。之后,我们没有更改 foo 的内容... foo [1] 仍然是 null

在Android上呢?

在Android上,追踪NPE的直接原因更简单。例外消息通常会告诉您您使用的的null引用的(编译时间)类型和在投掷NPE时试图调用的方法。这简化了查明直接原因的过程。

但是另一方面,Android具有一些NPE的常见平台特异性原因。一个非常常见的是 getViewById 出乎意料地返回 null 。我的建议是搜索Q&amp;关于意外 null 返回值的原因。

Question: What causes a NullPointerException (NPE)?

As you should know, Java types are divided into primitive types (boolean, int, etc.) and reference types. Reference types in Java allow you to use the special value null which is the Java way of saying "no object".

A NullPointerException is thrown at runtime whenever your program attempts to use a null as if it was a real reference. For example, if you write this:

public class Test {
    public static void main(String[] args) {
        String foo = null;
        int length = foo.length();   // HERE
    }
}

the statement labeled "HERE" is going to attempt to run the length() method on a null reference, and this will throw a NullPointerException.

There are many ways that you could use a null value that will result in a NullPointerException. In fact, the only things that you can do with a null without causing an NPE are:

  • assign it to a reference variable or read it from a reference variable,
  • assign it to an array element or read it from an array element (provided that array reference itself is non-null!),
  • pass it as a parameter or return it as a result, or
  • test it using the == or != operators, or instanceof.

Question: How do I read the NPE stacktrace?

Suppose that I compile and run the program above:

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:4)
$

First observation: the compilation succeeds! The problem in the program is NOT a compilation error. It is a runtime error. (Some IDEs may warn your program will always throw an exception ... but the standard javac compiler doesn't.)

Second observation: when I run the program, it outputs two lines of "gobbledy-gook". WRONG!! That's not gobbledy-gook. It is a stacktrace ... and it provides vital information that will help you track down the error in your code if you take the time to read it carefully.

So let's look at what it says:

Exception in thread "main" java.lang.NullPointerException

The first line of the stack trace tells you a number of things:

  • It tells you the name of the Java thread in which the exception was thrown. For a simple program with one thread (like this one), it will be "main". Let's move on ...
  • It tells you the full name of the exception that was thrown; i.e. java.lang.NullPointerException.
  • If the exception has an associated error message, that will be output after the exception name. NullPointerException is unusual in this respect, because it rarely has an error message.

The second line is the most important one in diagnosing an NPE.

at Test.main(Test.java:4)

This tells us a number of things:

  • "at Test.main" says that we were in the main method of the Test class.
  • "Test.java:4" gives the source filename of the class, AND it tells us that the statement where this occurred is in line 4 of the file.

If you count the lines in the file above, line 4 is the one that I labeled with the "HERE" comment.

Note that in a more complicated example, there will be lots of lines in the NPE stack trace. But you can be sure that the second line (the first "at" line) will tell you where the NPE was thrown1.

In short, the stack trace will tell us unambiguously which statement of the program has thrown the NPE.

See also: What is a stack trace, and how can I use it to debug my application errors?

1 - Not quite true. There are things called nested exceptions...

Question: How do I track down the cause of the NPE exception in my code?

This is the hard part. The short answer is to apply logical inference to the evidence provided by the stack trace, the source code, and the relevant API documentation.

Let's illustrate with the simple example (above) first. We start by looking at the line that the stack trace has told us is where the NPE happened:

int length = foo.length(); // HERE

How can that throw an NPE?

In fact, there is only one way: it can only happen if foo has the value null. We then try to run the length() method on null and... BANG!

But (I hear you say) what if the NPE was thrown inside the length() method call?

Well, if that happened, the stack trace would look different. The first "at" line would say that the exception was thrown in some line in the java.lang.String class and line 4 of Test.java would be the second "at" line.

So where did that null come from? In this case, it is obvious, and it is obvious what we need to do to fix it. (Assign a non-null value to foo.)

OK, so let's try a slightly more tricky example. This will require some logical deduction.

public class Test {

    private static String[] foo = new String[2];

    private static int test(String[] bar, int pos) {
        return bar[pos].length();
    }

    public static void main(String[] args) {
        int length = test(foo, 1);
    }
}

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.test(Test.java:6)
    at Test.main(Test.java:10)
$ 

So now we have two "at" lines. The first one is for this line:

return args[pos].length();

and the second one is for this line:

int length = test(foo, 1);
    

Looking at the first line, how could that throw an NPE? There are two ways:

  • If the value of bar is null then bar[pos] will throw an NPE.
  • If the value of bar[pos] is null then calling length() on it will throw an NPE.

Next, we need to figure out which of those scenarios explains what is actually happening. We will start by exploring the first one:

Where does bar come from? It is a parameter to the test method call, and if we look at how test was called, we can see that it comes from the foo static variable. In addition, we can see clearly that we initialized foo to a non-null value. That is sufficient to tentatively dismiss this explanation. (In theory, something else could change foo to null ... but that is not happening here.)

So what about our second scenario? Well, we can see that pos is 1, so that means that foo[1] must be null. Is this possible?

Indeed it is! And that is the problem. When we initialize like this:

private static String[] foo = new String[2];

we allocate a String[] with two elements that are initialized to null. After that, we have not changed the contents of foo ... so foo[1] will still be null.

What about on Android?

On Android, tracking down the immediate cause of an NPE is a bit simpler. The exception message will typically tell you the (compile time) type of the null reference you are using and the method you were attempting to call when the NPE was thrown. This simplifies the process of pinpointing the immediate cause.

But on the flipside, Android has some common platform-specific causes for NPEs. A very common is when getViewById unexpectedly returns a null. My advice would be to search for Q&As about the cause of the unexpected null return value.

梦旅人picnic 2025-01-25 12:30:53

这就像您正在尝试访问一个 null 的对象。考虑下面的例子:

TypeA objA;

此时您刚刚声明这个对象,但还没有初始化或实例化。每当您尝试访问其中的任何属性或方法时,它都会抛出 NullPointerException ,这是有道理的。

另请参阅下面的示例:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

It's like you are trying to access an object which is null. Consider below example:

TypeA objA;

At this time you have just declared this object but not initialized or instantiated. And whenever you try to access any property or method in it, it will throw NullPointerException which makes sense.

See this below example as well:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
热情消退 2025-01-25 12:30:53

当应用程序在需要对象的情况下尝试使用 null 时,会引发空指针异常。其中包括:

  1. 调用 null 对象的实例方法。
  2. 访问或修改 null 对象的字段。
  3. null 的长度视为数组。
  4. 访问或修改 null 的槽,就像它是一个数组一样。
  5. 抛出 null 就好像它是 Throwable 值一样。

应用程序应该抛出此类的实例来指示 null 对象的其他非法使用。

参考: http://docs.oracle.com/javase /8/docs/api/java/lang/NullPointerException.html

A null pointer exception is thrown when an application attempts to use null in a case where an object is required. These include:

  1. Calling the instance method of a null object.
  2. Accessing or modifying the field of a null object.
  3. Taking the length of null as if it were an array.
  4. Accessing or modifying the slots of null as if it were an array.
  5. Throwing null as if it were a Throwable value.

Applications should throw instances of this class to indicate other illegal uses of the null object.

Reference: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

淡笑忘祈一世凡恋 2025-01-25 12:30:53

null 指针是指无处不在的。当您取消指针 p 时,您说“给我存储在“ P”中的位置。 ,存储在 p 的位置是 ,您说的是“在位置'无处可去的数据,所以它显然无法做到这一点。它抛出 null指针异常

A null pointer is one that points to nowhere. When you dereference a pointer p, you say "give me the data at the location stored in "p". When p is a null pointer, the location stored in p is nowhere, you're saying "give me the data at the location 'nowhere'". Obviously, it can't do this, so it throws a null pointer exception.

In general, it's because something hasn't been initialized properly.

一梦等七年七年为一梦 2025-01-25 12:30:53

已经有很多解释来解释它是如何发生以及如何修复它的,但是您也应该遵循最佳实践避免 nullpointerexpiption

参见:
最佳实践

我会补充一点,非常重要,可以很好地利用 final 修饰符。
使用“最终”

修饰符:

  1. 使用 final 修饰符来执行良好的初始化。
  2. 避免在方法中返回null,例如适用时返回空收集。
  3. 使用注释 @Nullable
  4. 快速失败,并使用断言在整个应用程序不应为null时避免通过整个应用程序传播Null对象。
  5. 首先使用已知对象的平等: if(“ nownobject” .equals(unknownobject)
  6. peave valueof()而不是 toString()
  7. 使用null SAFE 方法 stringutils.isempty(null)
  8. 使用Java 8可选作为方法中的返回值,可选类为表示可选值而不是null引用提供了解决方案。

A lot of explanations are already present to explain how it happens and how to fix it, but you should also follow best practices to avoid NullPointerExceptions at all.

See also:
A good list of best practices

I would add, very important, make a good use of the final modifier.
Using the "final" modifier whenever applicable in Java

Summary:

  1. Use the final modifier to enforce good initialization.
  2. Avoid returning null in methods, for example returning empty collections when applicable.
  3. Use annotations @NotNull and @Nullable
  4. Fail fast and use asserts to avoid propagation of null objects through the whole application when they shouldn't be null.
  5. Use equals with a known object first: if("knownObject".equals(unknownObject)
  6. Prefer valueOf() over toString().
  7. Use null safe StringUtils methods StringUtils.isEmpty(null).
  8. Use Java 8 Optional as return value in methods, Optional class provide a solution for representing optional values instead of null references.
旧人 2025-01-25 12:30:53

NULL指针异常是您使用对象而不初始化对象的指标。

例如,以下是一个学生课,它将在我们的代码中使用它。

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

以下代码为您提供了空指针异常。

public class School {

    Student student;

    public School() {
        try {
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

因为您正在使用 student ,但您忘了像在
正确的代码如下:

public class School {

    Student student;

    public School() {
        try {
            student = new Student();
            student.setId(12);
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

A null pointer exception is an indicator that you are using an object without initializing it.

For example, below is a student class which will use it in our code.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

The below code gives you a null pointer exception.

public class School {

    Student student;

    public School() {
        try {
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

Because you are using student, but you forgot to initialize it like in the
correct code shown below:

public class School {

    Student student;

    public School() {
        try {
            student = new Student();
            student.setId(12);
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}
゛清羽墨安 2025-01-25 12:30:53

在Java中,所有内容(不包括原始类型)都是类的形式。

如果要使用任何对象,则有两个阶段:

  1. 声明
  2. 初始化

示例:

  • 声明: object;
  • 初始化: object = new Object();

对于数组概念:

  • 声明: item Item [] =新项目[5];
  • 初始化: item [0] = new Item();

如果您不给出初始化部分,则 NullPoInterException 出现。

In Java, everything (excluding primitive types) is in the form of a class.

If you want to use any object then you have two phases:

  1. Declare
  2. Initialization

Example:

  • Declaration: Object object;
  • Initialization: object = new Object();

Same for the array concept:

  • Declaration: Item item[] = new Item[5];
  • Initialization: item[0] = new Item();

If you are not giving the initialization section then the NullPointerException arise.

拥醉 2025-01-25 12:30:53

java 您声明的所有变量实际上是“参考”原语)而不是对象本身。

当您尝试执行一个对象方法时,参考要求生存对象执行该方法。但是,如果引用是引用null(零,零,void,nada),则无法执行该方法。然后,运行时让您通过扔一个NullPoInterException知道这一点。

您的引用是“指向” null,因此“指向”。

该对象生活在VM内存空间中,访问它的唯一方法是使用 this 引用。举此示例:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

在您的代码中的另一个位置:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

这是一个重要的事情 - 当不再对对象引用时(在上面的示例参考 and 其他retherference 两个指向null),然后该对象是“无法到达的”。我们无法使用它,因此该对象准备好收集垃圾,在某些时候,VM将释放此对象使用的内存并分配另一个。

In Java all the variables you declare are actually "references" to the objects (or primitives) and not the objects themselves.

When you attempt to execute one object method, the reference asks the living object to execute that method. But if the reference is referencing NULL (nothing, zero, void, nada) then there is no way the method gets executed. Then the runtime let you know this by throwing a NullPointerException.

Your reference is "pointing" to null, thus "Null -> Pointer".

The object lives in the VM memory space and the only way to access it is using this references. Take this example:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

And on another place in your code:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

This an important thing to know - when there are no more references to an object (in the example above when reference and otherReference both point to null) then the object is "unreachable". There is no way we can work with it, so this object is ready to be garbage collected, and at some point, the VM will free the memory used by this object and will allocate another.

非要怀念 2025-01-25 12:30:53

另一种 NullPointerException 情况发生在声明一个对象数组,然后立即尝试取消引用其中的元素时。

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

如果颠倒比较顺序,就可以避免这种特定的 NPE;即,在保证非空对象上使用 .equals

数组内的所有元素 初始化为其共同的初始值;对于任何类型的对象数组,这意味着所有元素均为 null

在访问或取消引用数组中的元素之前,您必须先初始化它们。

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

Another occurrence of a NullPointerException occurs when one declares an object array, then immediately tries to dereference elements inside of it.

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

This particular NPE can be avoided if the comparison order is reversed; namely, use .equals on a guaranteed non-null object.

All elements inside of an array are initialized to their common initial value; for any type of object array, that means that all elements are null.

You must initialize the elements in the array before accessing or dereferencing them.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文