什么是NullPointerException,以及如何解决它?
什么是空指针异常( java.lang.NullPointerException
)以及导致它们的原因?
可以使用哪些方法/工具来确定原因,以便阻止异常导致程序过早终止?
当你声明一个引用变量(即一个对象)时,你真的创建了一个指向对象的指针。 在声明基本类型int
的变量时考虑以下代码:
int x;
x = 10;
在这个例子中,变量x是一个int
,Java会将它初始化为0。 当你在第二行中将它赋值为10时,你的值10被写入x所指向的内存位置。
但是,当您尝试声明引用类型时会发生不同的事情。 采取以下代码:
Integer num;
num = new Integer(10);
第一行声明一个名为num
的变量,但它不包含原始值。 相反,它包含一个指针(因为类型是Integer
,它是一个引用类型)。 既然你还没有说Java到底指向什么,它意味着“ 我没有指向任何东西 ”。
在第二行中, new
关键字用于实例化(或创建)Integer类型的对象,并且指针变量num
被分配给该对象。 现在可以使用解引用操作符来引用该对象.
(一个点)。
当您声明一个变量但未创建对象时,您询问的Exception
就会发生。 如果您尝试在创建对象之前解除引用num
,则会得到NullPointerException
。 在最微不足道的情况下,编译器会捕获这个问题,并让你知道“num可能没有被初始化”,但有时你会编写不直接创建对象的代码。
例如,你可能有一个方法如下:
public void doSomething(SomeObject obj) {
//do something to obj
}
在这种情况下,您不是创建对象obj
,而是假定它是在doSomething
方法被调用之前创建的。 不幸的是,可以像这样调用方法:
doSomething(null);
在这种情况下, obj
为null。 如果该方法旨在对传入的对象执行某些操作,则抛出NullPointerException
是合适的,因为这是程序员错误,程序员将需要该信息用于调试目的。
或者,可能会出现这样的情况:方法的目的不仅仅是对传入的对象进行操作,因此可能接受空参数。 在这种情况下,您需要检查一个空参数并且行为不同。 你也应该在文档中解释这一点。 例如, 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
}
}
最后,如何使用堆栈跟踪查明异常和原因
NullPointerException
是当您尝试使用指向内存中没有位置的引用(空)时发生的异常,就好像它正在引用对象一样。 在空引用上调用方法或尝试访问空引用的字段将触发NullPointerException
。 这些是最常见的,但在NullPointerException
javadoc页面上列出了其他方法。
可能是我可以用来说明NullPointerException
的最快的示例代码是:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
在main
的第一行,我明确地将Object
reference obj
设置为null
。 这意味着我有一个参考,但它不指向任何对象。 在那之后,我尝试将引用视为通过调用一个方法来指向一个对象。 这会导致NullPointerException
因为在引用指向的位置没有要执行的代码。
(这是一个技术性问题,但我认为它提到了:指向null的引用与指向无效内存位置的C指针不同。空指针实际上并不指向任何地方,这与指向不同的指向一个恰好无效的位置。)
什么是NullPointerException?
JavaDocs是一个很好的开始。 他们涵盖了这些内容:
当应用程序尝试在需要对象的情况下使用null时抛出。 这些包括:
应用程序应该抛出此类的实例来指示其他非法使用null对象。
同样的情况是,如果您尝试使用带有synchronized
的空引用,那么也会根据JLS引发此异常:
SynchronizedStatement:
synchronized ( Expression ) Block
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();
}
}
识别空值
第一步是准确识别哪些值导致异常。 为此,我们需要做一些调试。 学习阅读堆栈跟踪很重要。 这会告诉你抛出异常的地方:
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
方法中)。 查看该行并通过添加日志语句或使用调试器来检查哪些值为空。 我们发现s
是空的,调用它的length
方法会抛出异常。 当s.length()
从方法中移除时,我们可以看到程序停止抛出异常。
跟踪这些值来自哪里
接下来检查这个值来自哪里。 通过跟随方法的调用者,我们看到s
在print()
方法中使用printString(name)
传入,并且this.name
为null。
跟踪应该设置这些值的位置
this.name
在哪里设置? 在setName(String)
方法中。 通过更多的调试,我们可以看到这个方法根本不被调用。 如果调用该方法,请确保检查这些方法的调用顺序,并且在打印方法之后不调用set方法。
这足以给我们一个解决办法:加入到呼叫printer.setName()
调用之前printer.print()
其他修补程序
该变量可以有一个默认值(并且setName
可以防止它被设置为null):
private String name = "";
print
或者printString
方法可以检查null,例如:
printString((name == null) ? "" : name);
或者你可以设计这个类,使得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();
}
}
也可以看看:
我仍然无法找到问题
如果您尝试调试问题并且仍然没有解决方案,可以发布一个问题以获得更多帮助,但请确保包含迄今为止尝试的内容。 至少在问题中包含堆栈跟踪 ,并在代码中标记重要的行号 。 另外,请先尝试简化代码(请参阅SSCCE)。
链接地址: http://www.djcxy.com/p/13309.html