

StackOverflow-translation/what-is-a-nullpointerexception-and-how-do-i-fix-it.md...
source link: https://github.com/c-rainstorm/StackOverflow-translation/blob/master/Java/what-is-a-nullpointerexception-and-how-do-i-fix-it.md?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

什么是空指针异常,如何修正它
An Example
当声明一个引用变量时,实际上我们获得的是指向这个变量的指针。下面的代码声明了一个 int
类型的变量:
int x;
x = 10;
变量 x
为 int
,Java 会在声明时将其初始化为 0(在栈上)。当 x = 10
执行时,10
就会被写到变量 x
所指向的内存位置。
但是当声明一个引用类型的变量时就不一样了,看下面的代码:
Integer num;
num = new Integer(10);
第一行声明了一个变量 num
,但是它是一个引用类型,但是此时我们并未给他赋值,这时他什么都没有引用。
第二行创建了一个 Integer
类型的对象,并且把这个对象的引用赋给 num
。此时我们就可以通过 .
来访问这个对象了。
NullPointerException
发生在声明了变量,但是没有创建对象。如果试图在创建对象前访问 num
变量,就会产生一个 NullPointerException
。大多数时候编译器会发现这个问题,并给出提示;但是有时候你并没有直接去创建这个对象,而是直接使用。对于这种情况:
public void doSomething(SomeObject obj){
//do something to obj
}
这种情况下并没有直接创建 obj
对象,而是假设在方法调用以前已经创建好了。但是有时会用这种方式来调用这个方法
doSomething(null);
这时 obj
就是 null
。如果这个方法要对�传进来的对象进行操作,那么这时抛出 NullPointerException
是比较合适的。因为这是程序员的责任并且程序员需要这个信息来做调试。
另外,如果这个方法并不一定要对这个对象进行操作,那么此时空指针可能是可以接受的。在这种情况下,你需要去检测空指针,并且在文档中给出说明。一个例子:
/**
* @param ojb 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
}
}
What is NullPointerException
当应用程序试图在本应该使用对象的时候使用了 null
时,会抛出该异常。这些情况有:
- 试图调用
null
对象的实例方法。 - 访问或修改
null
对象的域。 - 当
null
对象的类型是数组时,试图获取其长度。 - 当
null
对象的类型是数组时,试图访问或修改其中元素。 - 主动抛出
null
对象时。
应用程序应该抛出 NullPointerException
类型的实例来暗示 null
对象的其他不合法使用。NullPointerException
也可以由虚拟机构造。
SynchronizedStatement:
synchronized( Expression ) Block
当 Expression
为 null
时,也会抛出该异常。
how do we fix it
看一个例子:
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
第一步是精确定位哪个值导致这个异常。学会去读栈轨迹非常重要,他会告诉你这个异常是从哪里抛出的:
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
。这个地方我们发现 s
是 null
, 并且调用了 length()
方法。当 s.length()
语句删除以后就不会再抛出这个异常了。
Trace where these values come from
第二步是检查这个空值是从哪里传过来的。通过沿着方法的调用栈向上查找,我么可以看到 s
是在 print()
方法中调用 printString(name)
来传入的,但是 this.name
是 null
。
Trace where these values should be set
this.name
通过 setName(String )
方法来设置。但是我们发现这个方法根本没有调用。如果这个方法被调用了,确保这些方法调用的顺序是正确的,也就是 setName()
方法要在 print()
方法之前调用。
这些信息足够我们解决这个问题了:在 printer.print()
之前添加 printer.setName()
方法调用
Other fixes
给变量一个默认值:
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();
}
}
Best Practice
- 使用
final
修饰变量来强制初始化 - 避免从方法中返回
null
,例如返回空集合。 - 使用注解
@NotNull
和Nullable
。 - 快速失败并且使用
assert
来防止null
对象在整个应用程序中传播。 - 使用
equals()
方法时,已知的对象在前:if("knownObject".equals(unknownObject))
- 使用
valueOf()
而不是toString()
- 使用工具类方法进行判断:
Objects.isNull(null);
- 对于那些并不由你创建的对象,总是检测
null
。如果调用者传了null
,但是null
不是一个合法的参数,那么应该抛出异常给调用者。简单的忽略不合法输入隐藏了代码中的问题,应该禁止这么做。
Reference
Recommend
-
60
Mikko,Prity,李相允
-
84
spring aop 使用 cglib 引起的空指针 NullPointerException 问题 产生空指针的代码如下: HibernateDaoSupport.java 代码如下: public abstract class Hibern...
-
54
每日一问-Android-20181031 为什么 HTTP Code 204 会导致 Retrofit 出现 NullPointerException? 答: 今天在做网络接口的时候, 一个返回结果应该是 Map 的接口出现了异常:
-
36
Summary NullPointerExceptions are freqently encountered developing or maintaining a Java application. NullPointerExceptions often don't contain a message. This complicates finding the cause of the exception.
-
58
-
46
-
34
2020年3月17日发布,Java正式发布了JDK 14 ,目前已经可以开放下载。在JDK 14中,共有16个新特性,本文主要来介绍其中的一个特性:JEP 358: Helpful NullPointerExceptions null何错之有? 对于Java程序员来说,null...
-
32
在Java语言中,处理空指针往往是一件很头疼的事情,一不小心,说不定就搞出个线上Bug,让你的绩效考核拿到3.25。最近新出的Java14,相信大家都有所耳闻,那么今天就来看看,面对NullPointerException,Java14有哪些更好的处理方式呢?
-
4
在Java语言中,处理空指针往往是一件很头疼的事情,一不小心,说不定就搞出个线上Bug,让你的绩效考核拿到3.25。 最近新出的Java14,相信大家都有所耳闻,那么今天就来看看,面对NullPointerException,Java14有哪些更好的处理方式呢?...
-
13
null在Java中带来的麻烦 我相信所有的Java程序猿一定都遇到过 NullPointerException ,空指针在Java程序中是最常见的,也是最烦人的;它让我们很多程序猿产生了根深蒂固的感觉,所有可能产生空指针的地方都...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK