gpt4 book ai didi

What is a NullPointerException, and how do I fix it?(什么是NullPointerException,我该如何修复它?)

转载 作者:bug小助手 更新时间:2023-10-22 16:38:57 26 4
gpt4 key购买 nike




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

什么是空指针异常(java.lang.NullPointerException),是什么导致了它们?



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

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


更多回答
优秀答案推荐

There are two overarching types of variables in Java:

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的变量,但不初始化它:


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.

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


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).

这就是事情变得有趣的地方。引用变量可以设置为null,这意味着“我没有引用任何内容”。如果您明确地以这种方式设置引用变量,或者引用变量未初始化且编译器未捕获它,则可以在引用变量中获得null值(Java将自动将变量设置为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.

如果您显式地或通过Java自动将引用变量设置为null,并且您试图取消引用它,则会得到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.

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


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.

第一行声明了一个名为num的变量,但它实际上还没有包含引用值。由于您还没有说明要指向什么,Java将其设置为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.

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


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.

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


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:

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


doSomething(null);

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

在这种情况下,obj为null,语句obj.myMethod()将抛出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.

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


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:

除了由于方法的逻辑而引发的NullPointerExceptions之外,您还可以检查方法参数中的null值,并通过在方法开头附近添加以下内容来显式抛出NPE:


// 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.

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


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:

或者,在某些情况下,方法的目的可能不仅仅是对传入的对象进行操作,因此可以接受null参数。在这种情况下,您需要检查一个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
}
}

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

带有查找错误的声纳可以检测NPE。声纳可以动态捕捉JVM引起的空指针异常吗


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.

现在Java14添加了一个新的语言特性来显示NullPointerException的根本原因。自2006年以来,此语言功能一直是SAP商业JVM的一部分。


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

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



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:

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



  • 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.

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



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

    当foo为null时,switch(foo){…}(无论是表达式还是语句)都可以引发NullPointerException。



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

    foo.new SomeInnerClass()在foo为null时抛出NullPointerException。



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

    当name1或primaryExpression的求值结果为null时,形式为name1::name2或primaryExpression::name的方法引用在求值时引发NullPointerException。


    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!

    这里JLS的一个注释说,someInstance.someStaticMethod()不会抛出NPE,因为someStaticMethod是静态的,但someInstance::someStaticMethod仍然抛出NPE!




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

*请注意,JLS可能也间接地谈到了很多关于NPE的内容。



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.

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


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

可能我能想出的最快的示例代码来说明NullPointerException是:


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.

在main中的第一行,我显式地将Object引用obj设置为null。这意味着我有一个引用,但它没有指向任何对象。之后,我试图通过调用引用上的方法,将其视为指向对象。这会导致NullPointerException,因为在引用所指向的位置没有可执行的代码。


(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.)

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



What is a NullPointerException?



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

一个好的起点是JavaDocs。他们涵盖了以下内容:




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:

同样的情况是,根据JLS,如果您尝试使用synchronized的null引用,也会引发此异常:




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:

所以您有一个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();
}
}


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.

在这里,我们看到异常是在第13行抛出的(在printString方法中)。查看该行并通过添加日志记录语句或使用调试器来检查哪些值为null。我们发现s为null,对其调用length方法会引发异常。我们可以看到,当s.length()从方法中删除时,程序停止抛出异常。



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.

接下来检查该值的来源。通过跟踪该方法的调用方,我们可以看到s在print()方法中与printString(name)一起传入,而this.name为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.

这个名字集在哪里?在setName(String)方法中。通过更多的调试,我们可以看到这个方法根本没有被调用。如果调用了方法,请确保检查这些方法的调用顺序,并且set方法不会在print方法之后调用。



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

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



Other fixes



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

变量可以有一个默认值(setName可以防止它被设置为null):



private String name = "";


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

print或printString方法都可以检查null,例如:



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


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

或者,您可以设计类,使名称始终具有非null值:



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).

如果你试图调试问题,但仍然没有解决方案,你可以发布一个问题来获得更多帮助,但一定要包括你迄今为止尝试的内容。至少,在问题中包括堆栈,并在代码中标记重要的行号。此外,请先尝试简化代码(请参阅SSCCE)。



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".

众所周知,Java类型分为基元类型(boolean、int等)和引用类型。Java中的引用类型允许您使用特殊值null,这是Java表示“无对象”的方式。


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:

每当程序试图将null用作实际引用时,就会在运行时抛出NullPointerException。例如,如果您这样写:


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.

标记为“HERE”的语句将尝试在null引用上运行length()方法,这将引发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:

有很多方法可以使用会导致NullPointerException的null值。事实上,在不引起NPE的情况下,您可以对null执行的唯一操作是:



  • 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.)

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


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.

第二条线是诊断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.

如果你计算上面文件中的行数,第4行就是我用“HERE”注释标记的那一行。


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.

请注意,在一个更复杂的示例中,NPE堆栈跟踪中会有很多行。但你可以肯定的是,第二行(第一行“at”)会告诉你NPE是在哪里抛出的1。


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

简而言之,堆栈跟踪将明确地告诉我们程序的哪个语句抛出了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...

1-不完全正确。有些东西叫做嵌套异常。。。


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.

这是最困难的部分。简单的答案是将逻辑推理应用于堆栈跟踪、源代码和相关API文档提供的证据。


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:

让我们先用上面的简单例子来说明。我们从堆栈跟踪告诉我们的NPE发生的地方开始:


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

How can that throw an NPE?

那怎么能抛出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!

事实上,只有一种方法:只有当foo的值为null时,才会发生这种情况。然后,我们尝试在null和…上运行length()方法。。。砰!


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

但是(我听到你说)如果NPE被抛出到length()方法调用中呢?


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.

如果发生这种情况,堆栈跟踪看起来会有所不同。第一行“at”表示异常是在java.lang.String类的某一行中抛出的,Test.java的第4行将是第二行“at)”。


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.)

那么,那个null是从哪里来的呢?在这种情况下,这是显而易见的,我们需要做些什么来修复它也是显而易见的


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:

所以现在我们有两条“at”线。第一个是针对这一行的:


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:

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



  • 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.)

酒吧从哪里来?它是测试方法调用的一个参数,如果我们看看测试是如何调用的,我们可以看到它来自foo静态变量。此外,我们可以清楚地看到,我们将foo初始化为非null值。这足以暂时否定这一解释。(理论上,其他事情可能会将foo更改为null……但这在这里并没有发生。)


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?

那么我们的第二个场景呢?我们可以看到pos是1,这意味着foo[1]必须为null。这可能吗?


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.

我们为String[]分配两个初始化为null的元素。之后,我们没有更改foo。。。因此foo[1]将仍然为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.

在安卓系统上,追踪NPE的直接原因要简单一些。异常消息通常会告诉您正在使用的null引用的(编译时)类型,以及抛出NPE时试图调用的方法。这简化了找出直接原因的过程。


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.

但另一方面,Android有一些常见的平台特定的NPE原因。一种非常常见的情况是getViewById意外返回null。我的建议是搜索关于意外的null返回值的原因的QAs。



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

这就像你试图访问一个为null的对象。考虑以下示例:



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.

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



See this below example as well:

请参阅以下示例:



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


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

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




  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.

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



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

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



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.

空指针是指不指向任何地方的指针。当你取消引用一个指针p时,你会说“把存储在“p”中的位置的数据给我。当p是一个空指针时,存储在p中的位置不在任何地方,你就是在说“把‘无处’位置的数据交给我”。显然,它不能做到这一点,所以它抛出了一个空指示器异常。



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

一般来说,这是因为某些东西没有正确初始化。



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.

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



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

我想补充一点,非常重要的是,要充分利用最后的修饰语。在Java中使用“final”修饰符



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.



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:

因为您使用的是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");
}
}
}


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

在Java中,所有东西(不包括基元类型)都是类的形式。



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.

如果没有给出初始化部分,则会出现NullPointerException。



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

在Java中,您声明的所有变量实际上都是对对象(或基元)的“引用”,而不是对象本身。



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.

当您尝试执行一个对象方法时,引用会要求活动对象执行该方法。但是,如果引用引用的是NULL(nothing、zero、void、nada),那么就无法执行该方法。然后运行时通过抛出一个NullPointerException让您知道这一点。



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

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



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

对象位于VM内存空间中,访问它的唯一方法是使用这些引用。举个例子:



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.

这是一件需要知道的重要事情——当不再有对对象的引用时(在上面的例子中,当引用和otherReference都指向null时),则该对象是“不可访问的”。我们无法使用它,因此该对象已准备好进行垃圾收集,在某个时刻,VM将释放该对象使用的内存,并分配另一个内存。



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

当声明一个对象数组,然后立即尝试取消引用其中的元素时,就会出现另一个NullPointerException。



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.

如果比较顺序相反,则可以避免这种特定的NPE;即在保证的非null对象上使用.equals。



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.

数组中的所有元素都被初始化为它们的公共初始值;对于任何类型的对象数组,这意味着所有元素都为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));
}

更多回答

"The best way to avoid this type of exception is to always check for null when you did not create the object yourself." If the caller passes null, but null is not a valid argument for the method, then it's correct to throw the exception back at the caller because it's the caller's fault. Silently ignoring invalid input and doing nothing in the method is extremely poor advice because it hides the problem.

“避免这种类型的异常的最好方法是,当你自己没有创建对象时,总是检查null。”如果调用者传递了null,但null不是该方法的有效参数,那么将异常扔回调用者是正确的,因为这是调用者的错。默默地忽略无效输入而不在方法中执行任何操作是非常糟糕的建议,因为它隐藏了问题。

I would add a remark about this post explaining that even assignments to primitives can cause NPEs when using autoboxing: int a=b can throw an NPE if b is an Integer. There are cases where this is confusing to debug.

我想在这篇文章中添加一句话,解释在使用自动装箱时,即使是对基元的赋值也会导致NPE:如果b是Integer,int a=b可以抛出NPE。在某些情况下,调试起来会感到困惑。

Is it possible to capture NPE thrown by a webapp from the web browser?like will it show in the view page source from the web browser..

是否可以从网络浏览器捕获网络应用程序抛出的NPE?就像它会显示在web浏览器的查看页面源中一样。。

Yes check if the object equals null before you invoke a method on it or try to access a variable it might have. Some times structuring your code can help avoid null pointer exception. eg when checking an input string with a constant string you should start with the constant string like here: if ("SomeString".equals(inputString)) {} //even if inputString is null no exception is thrown. So there are a bunch of things that you can do to try to be safe.

是,在调用对象上的方法或尝试访问它可能具有的变量之前,请检查该对象是否等于null。有时结构化代码可以帮助避免空指针异常。例如,当用常量字符串检查输入字符串时,应该从常量字符串开始,如下所示:if(“SomeString”.equals(inputString)){}//即使inputString为null,也不会引发异常。因此,为了安全起见,你可以做很多事情。

An additional way of avoiding NullPointerException problems in your code is to use @Nullable and @NotNull annotations. The following answer has more information on this. Although this answer is specificially about the IntelliJ IDE, it is also applicable to other tools as is apparanet from teh comments. (BTW I am not allowed to edit this answer directly, perhaps the author can add it?)

避免代码中出现NullPointerException问题的另一种方法是使用@Nullable和@NotNull注释。以下答案提供了有关此方面的更多信息。尽管这个答案是针对IntelliJ IDE的,但它也适用于其他工具,正如从评论中显而易见的那样。(顺便说一句,我不允许直接编辑这个答案,也许作者可以添加它?)

I understood everything you wrote there, but only because I've been coding for a while and know what a 'pointer' and a 'reference' are (and what null is, for that matter). When I try to dive right into explanations like that, my students look at me crosseyed, because there's not enough background.

我理解你在那里写的所有内容,但这只是因为我已经编码了一段时间,知道什么是“指针”和“引用”(以及什么是null)。当我试图深入到这样的解释中时,我的学生们会瞪大眼睛看着我,因为没有足够的背景。

A more common way to get a NullPointerException in practice would be forgetting to explicitly initialize a member variable to something other than null before using it, like this. With local variables, the compiler would catch this error, but in this case it doesn't. Maybe that would make a useful addition to your answer?

在实践中,获得NullPointerException的一种更常见的方法是忘记在使用成员变量之前将其显式初始化为null以外的值,就像这样。对于局部变量,编译器会捕捉到这个错误,但在这种情况下不会。也许这会对你的答案有所帮助?

@EJP I think your points are valid, so I've updated the answer to be clearer and to avoid saying 'points to null' where it did.

@EJP我认为你的观点是有效的,所以我更新了答案,使其更加清晰,并避免在正确的地方说“指向null”。

@StevePowell I indicated a long time ago that I didn't want my answer to change. Please respect the intent of the original author.

@史蒂文·鲍威尔我很久以前就说过,我不希望我的答案改变。请尊重原作者的意图。

Sorry, I was "improving the answer" as requested in the top of this stackoverflow item (This question's answers are a collaborative effort: if you see something that can be improved, just edit the answer to improve it!) I disagree that your version is better, IMO @EJB has valid points; but you are quite welcome to keep your answer intact, confusing though it is.

对不起,我是按照这个stackoverflow项目顶部的要求“改进答案”的(这个问题的答案是一种合作:如果你看到了可以改进的东西,只需编辑答案来改进它!)我不同意你的版本更好,IMO@EJB有有效的点;但是,非常欢迎你保持你的答案完整,尽管它是令人困惑的。

@RuchirBaronia A debugger allows you to step through a program line by line to see which methods are called and how variables are changed. IDEs should have some tools to do this. See vogella.com/tutorials/EclipseDebugging/article.html for example.

@RuchirBaronia调试器允许您逐行遍历程序,查看调用了哪些方法以及如何更改变量。IDE应该有一些工具来做到这一点。例如,请参阅vogella.com/tutorials/EclipseDebuggin/article.html。

@RuchirBaronia You set breakpoints on the methods around any NullPointerExceptions as seen in the stacktrace, and check the values of variables against what you expect them to be. If you know a variable is null when it shouldn't be, then you can set breakpoints around any code that changes the value. There are also conditional breakpoints you can use which will tell you when a value changes.

@RuchirBaronia您可以在stacktrace中看到的任何NullPointerException周围的方法上设置断点,并根据您期望的值检查变量的值。如果您知道一个变量在不应该为null的时候为null,那么您可以在任何更改值的代码周围设置断点。您还可以使用条件断点,这些断点将在值更改时告诉您。

i suggest also static analysis tools, like FINDBUGS en.m.wikipedia.org/wiki/FindBugs

我还建议使用静态分析工具,如FINDBUGS en.m.wikipedia.org/wiki/FINDBUGS

If we give System.out.println(a.length()); // NullPointerException will be thrown, to skip this we can handle with try catch block. thank you

如果我们给System.out.println(a.length());//NullPointerException将被抛出,为了跳过这一点,我们可以用try-catch块来处理。非常感谢。

Keep it simple, I like this answer, add this if you consider correct - Access to uninitialized attribute of an object

保持简单,我喜欢这个答案,如果你认为正确的话,添加这个-访问对象的未初始化属性

@Emiliano - simply accessing an initialized attribute does not cause an NPE. It is what you >>do<< with the uninitialized attribute value that causes the NPE.

@Emiliano-简单地访问初始化的属性不会导致NPE。正是您>>对未初始化的属性值所做的操作导致了NPE。

If you want more cases: 1) using a null as the target of a synchronized block, 2) using a null as the target of a switch, and unboxing null.

如果您想要更多的情况:1)将null用作同步块的目标,2)将null作为开关的目标,并取消装箱null。

"A NULL pointer is one that points to nowhere" I disagree. Null pointers don't point to nowhere, they point to null values.

“空指针是指不指向任何地方的指针”我不同意。空指针不会指向任何地方,而是指向空值。

In j2ee projects,Nullpointer exception is very common.Some cases reference variables got null values.So You should check the variable initialization properly.And during conditional statement you should always check that flag or reference contains null or not like:- if(flag!=0) { ur code that uses flag }

在j2ee项目中,Nullpointer异常非常常见。有些情况下引用变量的值为null。因此,您应该正确检查变量初始化。在条件语句中,您应该始终检查标志或引用是否包含null或类似:-if(flag!=0){使用标志的ur代码}

It is worth mentioning that some IDEs (e.g. Eclipse) offer automatic nullity analisys based on customizable annotations (e.g. @Nullable as listed above) and warn about potential errors. It is also possible to infer and generate such annotations (e.g. IntelliJ can do that) based on existing code structure.

值得一提的是,一些IDE(例如Eclipse)提供了基于可定制注释的自动无效性分析(例如上面列出的@Nullable),并警告潜在的错误。还可以基于现有的代码结构来推断和生成这样的注释(例如IntelliJ可以这样做)。

First thing should do is before using a nullable object, you should check whether is it null, using if (obj==null).If it is null then you should write code to handle that also.

首先要做的是,在使用可为null的对象之前,您应该使用if(obj==null)检查它是否为null。如果它为null,那么您也应该编写代码来处理它。

IMO, it is preferable to avoid returning null objects in methods when possible and use annotation when null input parameters are not allowed in order to, by contract, reduce the amount of ´if (obj==null)´ in the code and improve the code readability.

IMO,为了减少代码中“if(obj==null)”的数量,提高代码的可读性,最好尽可能避免在方法中返回null对象,并在不允许null输入参数时使用注释。

Read this ... before you accept these "best practices" as truth: satisfice.com/blog/archives/27

阅读此。。。在你接受这些“最佳实践”为事实之前:confidence.com/blog/archives/27

While this is a nice example, may I ask what it adds to the question that isn't already covered by all the other answers?

虽然这是一个很好的例子,但我可以问一下,它为其他所有答案都没有涵盖的问题增加了什么吗?

It is simply inappropriate to use the word "uninitialized" here. The example you shown is in fact "initialized", and it is initialized with null. For uninitialized variables, compiler will complain to you.

在这里使用“未初始化”这个词是不合适的。您显示的示例实际上是“initialized”,它是用null初始化的。对于未初始化的变量,编译器会向您投诉。

A NullPointerException often occurs when calling method of an instance.For example, if you declare a reference but does not make it point to any instance, NullPointerException will happen when you call its method. such as: YourClass ref = null; // or ref = anotherRef; // but anotherRef has not pointed any instance ref.someMethod(); // it will throw NullPointerException. Generally fix it in this way: Before the method is called, determine whether the reference is null. such as: if (yourRef != null) { yourRef.someMethod(); }

调用实例的方法时经常会出现NullPointerException。例如,如果您声明了一个引用,但没有使其指向任何实例,则在调用其方法时将发生NullPointerException。例如:YourClass ref=null;//或ref=anotherRef;//但是另一个ref没有指向任何引用someMethod()的实例;//它将抛出NullPointerException。通常这样修复:在调用方法之前,确定引用是否为null。例如:if(yourRef!=null){yourRef.someMethod();}

Or use exception capture: such as: try { yourRef.someMethod(); } catch (NullPointerException e) { // TODO }

或者使用异常捕获:例如:try{yourRef.someMethod();}catch(NullPointerException e){//TODO}

operation on uninitialized object at instance level(not the class level) will lead to NullPointerException. operation need to be instance specific. if operation is at class level, saying calling a static method on uninitialized object then it will not throw NullPointerException exception. Even primitive wrapper class objects throws NullPointerException.

在实例级别(而不是类级别)对未初始化的对象执行操作将导致NullPointerException。操作需要是特定于实例的。若操作是在类级别,即在未初始化的对象上调用静态方法,那个么它不会抛出NullPointerException异常。即使是基元包装类对象也会抛出NullPointerException。

1. NullPointerException is a RuntimeException, that means will appear when your program is running, you will not at compilation time.! :(, but most of the IDE help you to discover this. 2. Minimize the use of the keyword 'null' in assignment statements. :) Reference url:

1.NullPointerException是一个RuntimeException,这意味着当你的程序运行时会出现,而在编译时不会出现。!:(,但大多数IDE都可以帮助您发现这一点。尽量减少在赋值语句中使用关键字“null”。:)引用url:

@tomj0101 I'm thoroughly unclear as to why you made that comment... But to your second point, a pattern before Optional was to return null. The keyword is fine. Knowing how to guard against it is critical. This offers one common occurrence of it and ways to mitigate it.

@tomj0101我完全不清楚你为什么这么说。。。但是到了第二点,Optional之前的模式是返回null。关键字很好。知道如何防范是至关重要的。这提供了一种常见的情况以及减轻这种情况的方法。

@Shomu: At what point do I even suggest that it should be caught?

@Shomu:我在什么时候建议应该抓住它?

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com