Answers:
声明引用变量(即对象)时,实际上是在创建指向对象的指针。考虑以下代码,您在其中声明基本类型的变量int
:
int x;
x = 10;
在此示例中,变量x
是an int
,Java会0
为您初始化它。当您10
在第二行为其分配值时,您的值将10
写入到所引用的存储位置中。x
。
但是,当您尝试声明引用类型时,会发生一些不同的事情。采取以下代码:
Integer num;
num = new Integer(10);
第一行声明了一个名为的变量num
,但实际上尚未包含原始值。相反,它包含一个指针(因为类型是Integer
引用类型)。由于您尚未说出要指向的内容,因此Java将其设置为null
,表示“ 我什么都没有指向 ”。
在第二行中,new
关键字用于实例化(或创建)一个类型的对象,Integer
并将指针变量num
分配给该Integer
对象。
NullPointerException
当您声明变量但未创建对象并在尝试使用变量的内容之前将其分配给变量时,就会发生这种情况(称为dereferencing)。因此,您指向的是实际上不存在的东西。
当.
用于访问方法或字段或[
用于索引数组时,通常会发生解除引用。
如果您尝试取消引用 num
在创建对象之前,则会得到一个NullPointerException
。在大多数情况下,编译器会发现问题,并让您知道“” num may not have been initialized
,但是有时您可能会编写不直接创建对象的代码。
例如,您可能具有如下方法:
public void doSomething(SomeObject obj) {
//do something to obj
}
在这种情况下,您不是要创建对象obj
,而是假设它是在对象之前创建的doSomething()
调用方法。注意,可以这样调用方法:
doSomething(null);
在这种情况下obj
为null
。如果该方法旨在对传入的对象做一些事情,则适当地抛出NullPointerException
因为这是程序员错误,程序员将需要该信息来进行调试。请在异常消息中包含对象变量的名称,例如
Objects.requireNonNull(a, "a");
替代地,在某些情况下,该方法的目的不仅是要对传入的对象进行操作,因此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
}
}
最后, 如何使用堆栈跟踪来查明异常和原因
可以使用哪些方法/工具确定原因,以阻止异常导致程序过早终止?
带有findbug的声纳可以检测NPE。 声纳能否动态捕获由JVM引起的空指针异常
int a=b
如果b为a,则可能引发NPE Integer
。在某些情况下,这会使调试感到困惑。
NullPointerException
代码出现问题的另一种方法是使用@Nullable
和@NotNull
注释。以下答案对此有更多信息。尽管此答案专门针对IntelliJ IDE,但它也适用于其他工具,如注释中的装置。(顺便说一句,我不允许直接编辑此答案,也许作者可以添加它?)
NullPointerException
s是例外,当您尝试使用指向内存中无位置(空)的引用时,就像在引用对象一样。在空引用上调用方法或尝试访问空引用的字段将触发NullPointerException
。这些是最常见的方法,但其他方法在NullPointerException
javadoc页面。
我想出的最快的示例代码可能NullPointerException
是:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
在其中的第一行main
,我将Object
参考值显式设置obj
为null
。这意味着我有一个引用,但它没有指向任何对象。之后,我尝试通过在其上调用方法来将引用当作指向对象的方式来对待。这导致NullPointerException
因为在引用指向的位置没有代码要执行。
(这是一种技术,但我认为值得一提:指向null的引用与指向无效内存位置的C指针不同。null指针实际上没有指向任何地方,这与指向恰好是无效的位置。)
null
使用它之前的其他变量,例如this。使用局部变量,编译器将捕获此错误,但在这种情况下则不会。也许这会对您的答案有所帮助?
JavaDocs是一个很好的起点。他们有以下内容:
当应用程序在需要对象的情况下尝试使用null时抛出。这些包括:
- 调用空对象的实例方法。
- 访问或修改空对象的字段。
- 将null的长度视为数组。
- 访问或修改null插槽,就好像它是一个数组一样。
- 将null视为Throwable值。
应用程序应抛出此类的实例,以指示对null对象的其他非法使用。
同样的情况是,如果您尝试使用带有null的引用synchronized
,则根据JLS也会抛出此异常:
SynchronizedStatement: synchronized ( Expression ) Block
- 否则,如果Expression的值为null,
NullPointerException
则抛出a。
所以你有一个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
方法中)引发了异常。查看该行,并通过添加日志记录语句或使用调试器来检查哪些值为空。我们发现它s
为null,并对其调用length
方法将引发异常。我们可以看到程序在以下情况下停止引发异常s.length()
从方法中删除。
追踪这些值的来源
接下来检查此值的来源。按照该方法的调用者,我们看到,s
在用传递printString(name)
的print()
方法,和this.name
为空。
跟踪应在何处设置这些值
在哪里this.name
设置?在setName(String)
方法上。通过更多的调试,我们可以看到根本没有调用此方法。如果调用了该方法,请确保检查这些方法的调用顺序,并且之后不调用set方法。在print方法方法。
这足以为我们提供解决方案:在呼叫printer.setName()
前将呼叫添加到printer.print()
。
该变量可以具有默认值(并setName
可以防止将其设置为null):
private String name = "";
任一print
或printString
方法可以检查空,例如:
printString((name == null) ? "" : name);
或者,您可以设计类,使其name
始终具有非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();
}
}
也可以看看:
如果您尝试调试问题而仍然没有解决方案,则可以发布问题以寻求更多帮助,但请确保包括到目前为止已尝试的内容。至少要在问题中包括stacktrace,并在代码中标记重要的行号。另外,请尝试首先简化代码(请参阅SSCCE)。
NullPointerException
(NPE)?正如你应该知道,Java的类型分为基本类型(boolean
,int
,等)和引用类型。Java中的引用类型使您可以使用特殊值null
,这是Java表示“无对象”的方式。
NullPointerException
只要您的程序尝试使用a null
,就好像它是真正的引用一样,在运行时引发A。例如,如果您编写此代码:
public class Test {
public static void main(String[] args) {
String foo = null;
int length = foo.length(); // HERE
}
}
标记为“ HERE”的语句将尝试length()
在null
引用上运行该方法,这将引发NullPointerException
。
您可以通过多种方式使用null
会导致的值NullPointerException
。实际上,在不引起NPE 的情况下,您可以做的唯一事情null
是:
==
或!=
运算符或对其进行测试instanceof
。假设我编译并运行了上面的程序:
$ 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.lang.NullPointerException
。NullPointerException
在这方面很不常见,因为它很少显示错误消息。第二行是诊断NPE时最重要的一行。
at Test.main(Test.java:4)
这告诉我们很多事情:
main
方法中Test
。如果您对上面文件中的行进行计数,则第4行是我用“ HERE”注释标记的行。
请注意,在一个更复杂的示例中,NPE堆栈跟踪中将有很多行。但是您可以确定第二行(第一行“ at”行)将告诉您NPE的抛出位置1。
简而言之,堆栈跟踪将明确地告诉我们该程序的哪个语句引发了NPE。
1-不太正确。有些事情称为嵌套异常...
这是困难的部分。简短的答案是对堆栈跟踪,源代码和相关API文档提供的证据进行逻辑推断。
让我们首先用一个简单的例子进行说明。我们首先查看堆栈跟踪告诉我们的那行是NPE发生的地方:
int length = foo.length(); // HERE
那怎么扔NPE?
实际上,只有一种方法:只有foo
具有value 才可能发生null
。然后,我们尝试length()
在null
... 上继续运行该方法!
但是(我听你说)如果将NPE扔到length()
方法调用中怎么办?
好吧,如果发生这种情况,堆栈跟踪看起来会有所不同。第一行“ at”表示java.lang.String
该类中的某行引发了异常,行的第4 Test.java
行将是第二行“ at”。
那是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
为非null值。这足以暂时驳斥该解释。(理论上,其他可能会更改 foo
为null
...,但此处未发生这种情况。)
那么我们的第二种情况呢?好吧,我们可以看到pos
is 1
,这意味着foo[1]
必须为null
。这可能吗?
的确是!这就是问题所在。当我们这样初始化时:
private static String[] foo = new String[2];
我们分配给a String[]
和两个初始化为的null
元素。在那之后,我们没有更改...的内容,foo
所以foo[1]
仍然会null
。
就像您要访问的对象是null
。考虑以下示例:
TypeA objA;
此时,您刚刚声明了该对象,但尚未初始化或实例化。而且,每当您尝试访问其中的任何属性或方法时,它都会抛出 NullPointerException
异常。
也请参见以下示例:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
当应用程序在需要对象的情况下尝试使用null时,将引发null指针异常。这些包括:
null
对象的实例方法。null
对象的字段。null
好像它是一个数组。null
就好像它是一个数组一样。null
好像它是一个Throwable值一样抛出。应用程序应抛出此类的实例以指示该null
对象的其他非法使用。
参考:http : //docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
null
作为synchronized
块的目标,2)使用a null
作为a 的目标switch
,然后拆箱null
。
一个null
指针是一个指向任何地方。当取消引用指针时p
,您说“将数据存储在“ p”中给我。当p
是null
指针时,存储的存储位置p
是nowhere
,则是说“将数据存储在“无处”中”。显然,它无法执行此操作,因此抛出null pointer exception
。
通常,这是因为某些东西没有正确初始化。
NULL
是用null
Java 编写的。这是区分大小写的事情。
已经有很多解释来解释它是如何发生的以及如何解决它,但是您还应该遵循最佳实践以避免NullPointerException
。
也可以看看: 最佳做法的好清单
我要补充一点,非常重要,要充分利用final
修饰符。
只要适用于Java,就使用“最终”修饰符
摘要:
final
修饰符强制执行良好的初始化。@NotNull
和@Nullable
if("knownObject".equals(unknownObject)
valueOf()
超过toString()
。StringUtils
方法StringUtils.isEmpty(null)
。@Nullable
上面列出的)提供自动的null analisys ,并警告潜在的错误。也可以基于现有代码结构来推断和生成此类注释(例如IntelliJ可以做到)。
if (obj==null)
。如果为null,则还应编写代码来处理该对象。
在Java中,所有内容(不包括基本类型)都是类的形式。
如果要使用任何对象,则有两个阶段:
例:
Object object;
object = new Object();
数组概念相同:
Item item[] = new Item[5];
item[0] = new Item();
如果您不提供初始化部分,则会NullPointerException
出现。
空指针异常表示您正在使用对象而未对其进行初始化。
例如,下面是一个学生班级,它将在我们的代码中使用它。
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");
}
}
}
在Java中,您声明的所有变量实际上都是对对象(或基元)的“引用”,而不是对象本身。
当您尝试执行一个对象方法时,引用将要求活动对象执行该方法。但是,如果引用引用的是NULL(无,零,无效,nada),则该方法将无法执行。然后,运行时将引发NullPointerException,让您知道这一点。
您的引用是“指向” null,因此是“ 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...
这方面的一个重要的事情要知道-当有一个对象(当在上面的例子中,没有更多的参考reference
和otherReference
随后的对象是“不可达”都指向空)。我们无法使用它,因此已准备好对该对象进行垃圾回收,并且在某些时候,VM将释放该对象使用的内存并分配另一个。
NullPointerException
当声明一个对象数组,然后立即尝试取消引用其中的元素时,会发生另一种a 发生。
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
如果比较顺序相反,则可以避免使用这种特定的NPE。即使用.equals
在有保证的非null对象上使用。
数组中的所有元素都初始化为它们的公共初始值;对于任何类型的对象数组,这意味着所有元素都是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));
}
Optional
是返回null。关键字很好。知道如何防范它是至关重要的。这提供了一种常见的情况以及减轻它的方法。