在逛 Stack Overflow 的时候,发现最火的问题竟然是:什么是 NullPointerException(java.lang.NullPointerException),它是由什么原因导致的,有没有好的方法或者工具可以追踪它发生的原因?
真没想到,这个问题浏览的次数多达 250 万次!所以,我想是时候把最高赞的回答整理一下分享出来了。请随我来。
声明引用变量(即对象)时,实际上是创建了一个指向对象的指针。请看以下代码:
int x;
x = 10;
但是呢,当我们尝试声明一个引用类型时,情况将会有所不同。
Integer
num;
num =
new Integer(
10);
第二行代码中,new 关键字创建了一个 Integer 类型的对象,并将变量 num 指向该对象。
当我们声明了一个变量,却没有将该变量指向任何创建的对象,然后就使用它的时候,NullPointerException 就发生了。大多数情况下,编译器会发现这个问题,并且提醒我们“xxxx may not have been initialized”。
假如有这样一段代码:
public void doSomething(SomeObject obj) {
//do something to obj
}
现在假设在此之前它没有创建。我们这样调用 doSomething() 方法:
doSomething(
null);
还有另外一种替代方法,判断 obj 是不是 null,如果是,就小心行事,做某些不会引起 NullPointerException 的事情;如果不是,就放心大胆地做该做的事情。
/**
* @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
}
}
简单来说,堆栈信息是应用程序在引发 Exception 时调用的方法列表,可以准确地定位到错误发生的根源。就像下面这样:
Exception
in
thread "
main"
java
.lang.NullPointerException
at
com
.example.myproject.Book.getTitle(
Book
.java
:16)
at
com
.example.myproject.Author.getBookTitles(
Author
.java
:25)
at
com
.example.myproject.Bootstrap.main(
Bootstrap
.java
:14)
at
com
.example.myproject.Book.getTitle(
Book
.java
:16)
15
public String getTitle() {
16 System.
out.println(title.toString());
17
return title;
18 }
有时候,应用程序会捕获一个异常,然后把它作为另外一种类型的异常抛出。就像下面这样:
34
public void getBookIds(int id) {
35
try {
36 book.getId(id);
// 这里可能会引发 NullPointerException
37 }
catch (NullPointerException e) {
38
throw
new IllegalStateException(
"A book has a null property", e)
39 }
40 }
Exception
in
thread "
main"
java
.lang.IllegalStateException:
A
book
has
a
null
property
at
com
.example.myproject.Author.getBookIds(
Author
.java
:38)
at
com
.example.myproject.Bootstrap.main(
Bootstrap
.java
:14)
Caused
by:
java
.lang.NullPointerException
at
com
.example.myproject.Book.getId(
Book
.java
:22)
at
com
.example.myproject.Author.getBookIds(
Author
.java
:36)
... 1
more
Caused
by:
java
.lang.NullPointerException <
-- 根本原因
at
com
.example.myproject.Book.getId(
Book
.java
:22)
有时候,堆栈信息要比上面的例子凌乱得多。参考下面这个。
javax.servlet.ServletException: Something bad happened
at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
at org.mortbay.jetty.servlet.ServletHandler
$CachedChain.doFilter(ServletHandler.java:1157)
at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28)
at org.mortbay.jetty.servlet.ServletHandler
$CachedChain.doFilter(ServletHandler.java:1157)
at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection
$RequestHandler.content(HttpConnection.java:943)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.jetty.bio.SocketConnector
$Connection.run(SocketConnector.java:228)
at org.mortbay.thread.QueuedThreadPool
$PoolThread.run(QueuedThreadPool.java:582)
Caused by: com.example.myproject.MyProjectServletException
at com.example.myproject.MyServlet.doPost(MyServlet.java:169)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler
$CachedChain.doFilter(ServletHandler.java:1166)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.context.ThreadLocalSessionContext
$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
at
$Proxy19.save(Unknown Source)
at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below)
at com.example.myproject.MyServlet.doPost(MyServlet.java:164)
... 32 more
Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s)
for column(s) MY_COLUMN
in statement [...]
at org.hsqldb.jdbc.Util.throwError(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
... 54 more
Caused
by:
java
.sql.SQLException:
Violation
of
unique
constraint
MY_ENTITY_UK_1:
duplicate
value(
s)
for
column(
s)
MY_COLUMN
in
statement
[...]
at
org
.hsqldb.jdbc.Util.throwError(
Unknown
Source)
at
org
.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(
Unknown
Source)
at
com
.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(
NewProxyPreparedStatement
.java
:105)
at
org
.hibernate.id.insert.AbstractSelec
at
com
.example.myproject.MyEntityService.save(
MyEntityService
.java
:59)
☞三年一跳槽、拒绝“唯学历”,火速 Get 这份程序员求生指南!
☞确认!语音识别大牛Daniel Povey将入职小米,曾遭霍普金斯大学解雇,怒拒Facebook
☞【又是一波重点】深度解析服务器科普知识 | CSDN博文精选
☞“国家队”入局! 中移动、银联等宣布区块链服务网络(BSN)正式内测!