<h2>什么是NullPointerException?</h2>
<p>一个好的开始是<a href="http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html" rel="noreferrer">JavaDocs</a>。他们包括:</p>
<blockquote>
<p>Thrown when an application attempts to use null in a case where an
object is required. These include:</p>
<ul>
<li>Calling the instance method of a null object.</li>
<li>Accessing or modifying the field of a null object.</li>
<li>Taking the length of null as if it were an array.</li>
<li>Accessing or modifying the slots of null as if it were an array.</li>
<li>Throwing null as if it were a Throwable value.</li>
</ul>
<p>Applications should throw instances of this class to indicate other
illegal uses of the null object.</p>
</blockquote>
<p>如果试图对<code>synchronized</code>使用空引用,也会引发此异常,<a href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.19" rel="noreferrer">per the JLS</a>:</p>
<blockquote>
<pre><code>SynchronizedStatement:
synchronized ( Expression ) Block
</code></pre>
<ul>
<li>Otherwise, if the value of the Expression is null, a <code>NullPointerException</code> is thrown.</li>
</ul>
</blockquote>
<h2>我该怎么修?</h2>
<p>所以你有一个<code>NullPointerException</code>。你怎么修的?举个简单的例子,抛出一个<code>NullPointerException</code>:</p>
<pre><code>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();
}
}
</code></pre>
<p><strong>识别空值</strong></p>
<p>第一步是准确识别导致异常的值<em>。为此,我们需要进行一些调试。学习阅读stacktrace</em>是很重要的。这将显示引发异常的位置:</p>
<pre><code>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)
</code></pre>
<p>这里,我们看到在第13行(在<code>printString</code>方法中)抛出了异常。查看行并检查哪些值为空
添加<em>日志语句</em>或使用<em>调试器</em>。我们发现<code>s</code>为空,对其调用<code>length</code>方法会引发异常。我们可以看到,当<code>s.length()</code>从方法中移除时,程序停止抛出异常。</p>
<p><strong>跟踪这些值的来源</p>
<p>下一步检查该值的来源。通过跟踪方法的调用方,我们可以看到<code>s</code>在<code>print()</code>方法中与<code>printString(name)</code>一起传入,并且<code>this.name</code>为空。</p>
<p><strong>跟踪应设置这些值的位置</p>
<p><code>this.name</code>集合在哪里?在<code>setName(String)</code>方法中。通过更多的调试,我们可以看到这个方法根本没有被调用。如果调用了方法,请确保检查调用这些方法的<em>顺序</em>,并且在打印方法</em>之后不调用set方法<em>。</p>
<p>这足以给我们一个解决方案:在调用<code>printer.print()</code>之前添加对<code>printer.setName()</code>的调用。</p>
<h2>其他修复</h2>
<p>变量可以有一个<em>默认值</em>(并且<code>setName</code>可以防止将其设置为空):</p>
<pre><code>private String name = "";
</code></pre>
<p><code>print</code>或<code>printString</code>方法都可以<em>检查null</em>,例如:</p>
<pre><code>printString((name == null) ? "" : name);
</code></pre>
<p>或者可以设计类,使<code>name</code><em>始终具有非空值</em>:</p>
<pre><code>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();
}
}
</code></pre>
<p><strong>另请参见:</strong></p>
<ul>
<li><a href="https://stackoverflow.com/questions/271526/avoiding-null-statements-in-java">Avoiding “!= null” statements in Java?</a></li>
</ul>
<h2>我还是找不到问题</h2>
<p>如果您试图调试问题,但仍然没有解决方案,您可以发布一个问题以获得更多帮助,但请确保包括您迄今为止所做的尝试。至少,<strong>在问题中包含stacktrace</strong>,并在代码中标记重要行号。另外,请先尝试简化代码(请参见<a href="http://sscce.org/" rel="noreferrer">SSCCE</a>)。</p>