什么是空指针异常(java.lang.NullPointerException),是什么原因导致的?
可以使用哪些方法/工具来确定原因,从而阻止异常导致程序过早终止?
什么是空指针异常(java.lang.NullPointerException),是什么原因导致的?
可以使用哪些方法/工具来确定原因,从而阻止异常导致程序过早终止?
当前回答
另一个NullPointerException发生在声明一个对象数组时,然后立即尝试解引用其中的元素。
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
如果比较顺序颠倒,则可以避免这种特定的NPE;也就是说,在一个有保证的非空对象上使用.equals。
数组中的所有元素都被初始化为它们共同的初始值;对于任何类型的对象数组,这意味着所有元素都是空的。
在访问或取消引用数组中的元素之前,必须初始化它们。
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
其他回答
在Java中有两种主要类型的变量:
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. 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.
考虑下面的代码,其中你声明了一个基本类型为int的变量,并且没有初始化它:
int x;
int y = x + x;
这两行会使程序崩溃,因为没有为x指定值,而我们正试图使用x的值来指定y。所有原语在被操作之前都必须初始化为可用的值。
现在事情变得有趣了。引用变量可以设置为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);
在这种情况下,obj为空,语句obj. mymethod()将抛出NullPointerException。
如果该方法打算像上面的方法那样对传入的对象做一些事情,那么抛出NullPointerException是合适的,因为这是一个程序员错误,程序员将需要该信息用于调试。
除了由方法逻辑引发的nullpointerexception异常,你还可以检查方法参数是否为空值,并通过在方法开头附近添加如下内容显式抛出npe:
// Throws an NPE with a custom error message if obj is null
Objects.requireNonNull(obj, "obj must not be null");
注意,在错误消息中清楚地说明哪个对象不能为空是很有帮助的。验证这一点的好处是:1)您可以返回自己更清晰的错误消息;2)对于方法的其余部分,您知道除非obj被重新赋值,否则它不是空的,可以安全地解除引用。
或者,在某些情况下,方法的目的不仅仅是对传入的对象进行操作,因此空参数可能是可以接受的。在这种情况下,您将需要检查空参数并采取不同的行为。您还应该在文档中对此进行解释。例如,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
}
}
最后,如何使用堆栈跟踪查明异常和原因
可以使用哪些方法/工具来确定原因,以便您停止 导致程序过早终止的异常?
声纳与发现漏洞可以检测到NPE。 声纳能捕捉JVM动态引起的空指针异常吗
现在Java 14添加了一个新的语言特性来显示NullPointerException的根本原因。该语言特性自2006年以来一直是SAP商业JVM的一部分。
在Java 14中,下面是一个示例NullPointerException异常消息:
java.lang.NullPointerException:不能调用"java.util.List.size()",因为"list"是空的
导致NullPointerException发生的情况列表
以下是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. 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!
*请注意,JLS可能也间接地说明了很多npe。
nullpointerexception是当您试图使用指向内存中任何位置(null)的引用时发生的异常,就好像它引用了一个对象一样。调用空引用上的方法或试图访问空引用的字段将触发NullPointerException异常。这些是最常见的方法,但是NullPointerException javadoc页面上列出了其他方法。
可能我能想出的最快的示例代码来说明NullPointerException将是:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
在main内部的第一行,我显式地将对象引用obj设置为null。这意味着我有一个引用,但它不指向任何对象。在此之后,我尝试通过调用对象上的方法来将引用视为指向对象。这将导致NullPointerException,因为在引用所指向的位置中没有代码要执行。
(这是一个技术细节,但我认为值得一提:指向null的引用与指向无效内存位置的C指针不同。空指针字面上不指向任何地方,这与指向一个恰好无效的位置有微妙的不同。)
当应用程序试图在需要对象的情况下使用null时,将引发空指针异常。这些包括:
调用空对象的实例方法。 访问或修改空对象的字段。 取null的长度,就好像它是一个数组一样。 访问或修改null的槽位,就像它是一个数组一样。 抛出null,就好像它是一个Throwable值。
应用程序应该抛出该类的实例,以指示null对象的其他非法使用。
参考:http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
这就像你试图访问一个为空的对象。考虑下面的例子:
TypeA objA;
此时,您刚刚声明了该对象,但尚未初始化或实例化。无论何时你试图访问其中的任何属性或方法,它都会抛出NullPointerException,这是有意义的。
请看下面的例子:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
空指针是指不指向任何地方的指针。当你对指针p进行解引用时,你说“给我存储在p中的位置的数据”。当p是一个空指针时,存储在p中的位置是无处不在的,你是在说“给我无处位置的数据”。显然,它不能这样做,所以它抛出一个空指针异常。
一般来说,这是因为某些东西没有正确地初始化。