在逛 Stack Overflow 的时候,发现最火的问题竟然是:什么是 NullPointerException( java.lang.NullPointerException),它是由什么原因导致的,有没有好的方法或者工具可以追踪它发生的原因?

真没想到,这个问题浏览的次数多达 250 万次!所以,我想是时候把最高赞的回答整理一下分享出来了。请随我来。

声明引用变量(即对象)时,实际上是创建了一个指向对象的指针。请看以下代码:

int x;
x = 10;

第一行代码声明了一个名为 x 的变量(int 类型),Java 会把它初始化为 0。第二行代码把 x 赋值为 10,意味着 10 将被写入到 x 所指向的内存位置上。

但是呢,当我们尝试声明一个引用类型时,情况将会有所不同。

Integer num;
num = new Integer(10);

第一行代码声明了一个名为 num 的变量(Integer 类型),Java 把它初始化为 null,表示“什么都没有指向 ”。

第二行代码中,new 关键字创建了一个 Integer 类型的对象,并将变量 num 指向该对象。

当我们声明了一个变量,却没有将该变量指向任何创建的对象,然后就使用它的时候,NullPointerException 就发生了。大多数情况下,编译器会发现这个问题,并且提醒我们“xxxx may not have been initialized”。

假如有这样一段代码:

public void doSomething(SomeObject obj) {//do something to obj
}

在这种情况下,我们没有创建对象 obj,而是假设它在 doSomething() 方法被调用之前就创建了。

现在假设在此之前它没有创建。我们这样调用 doSomething() 方法:

doSomething(null);

这就意味着 doSomething() 方法的参数 obj 为 null。如果该方法还要使用 obj 继续做点什么,最好提前抛出 NullPointerException,因为开发者需要该信息来进行调试。

还有另外一种替代方法,判断 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}
}

那假如程序真的出现了 NullPointerException,该怎么追踪堆栈信息,找到错误的根源呢?

简单来说,堆栈信息是应用程序在引发 Exception 时调用的方法列表,可以准确地定位到错误发生的根源。就像下面这样。

Exception in thread "main" java.lang.NullPointerExceptionat 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 ...”列表处,第一个“at 处”就是错误最初发生的位置。

at com.example.myproject.Book.getTitle(Book.java:16)

为了调试,我们可以打开 Book.java 类的第 16 行,它可能是:

15   public String getTitle() {
16      System.out.println(title.toString());
17      return title;
18   }

从这段代码中可以看得出,错误的原因很可能是因为 title 为 null。

有时候,应用程序会捕获一个异常,然后把它作为另外一种类型的异常抛出。就像下面这样:

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 propertyat com.example.myproject.Author.getBookIds(Author.java:38)at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerExceptionat com.example.myproject.Book.getId(Book.java:22)at com.example.myproject.Author.getBookIds(Author.java:36)... 1 more

和之前堆栈信息有所不同的是,这里多了一个“Caused by”;有时候还会有更多的“Caused by”。在这种情况下,我们通常需要追本溯源,找到最深层次的那个“cause”——它就是堆栈信息中最下面的那个。

Caused by: java.lang.NullPointerException <-- 根本原因at com.example.myproject.Book.getId(Book.java:22) 

同样,我们需要查看一下 Book.java 的第 22 行,找到可能引发 NullPointerException 的原因。

有时候,堆栈信息要比上面的例子凌乱得多。参考下面这个。

javax.servlet.ServletException: Something bad happenedat 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.MyProjectServletExceptionat 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

这个例子当中的堆栈信息实在是太多了,令人眼花缭乱。如果按照之前提供的方法(堆栈信息中最下面的那个)找最深层次的那个“cause”,它就是:

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

但其实它并不是的,因为抛出这个异常的方法调用者属于类库代码(c3p0 类库),所以我们需要往上找异常发生的原因,并且这个异常很可能是由我们自己编写的代码(com.example.myproject 包下)引发的,于是我们找到了这样一段异常信息。

at com.example.myproject.MyEntityService.save(MyEntityService.java:59)

顺藤摸瓜, 看看 MyEntityService.java 的第 59 行,它就是引发错误的根本原因。

Stack Overflow 上 250W 浏览量的一个问题:你对象丢了相关推荐

  1. java 如何跟多个字符串比较_Stack Overflow上370万浏览量的一个问题:如何比较Java的字符串...

    在逛 Stack Overflow 的时候,发现了一些访问量像喜马拉雅山一样高的问题,比如说这个:如何比较 Java 的字符串?访问量足足有 370万+,这不得了啊!说明有很多很多的程序员被这个问题困 ...

  2. Stack Overflow上最火的一段代码竟然有Bug

    作者 | Andreas Lundblad 译者 | 弯月     责编 | 欧阳姝黎 出品 | CSDN(ID:CSDNnews) 2010年的某一天,我忙中偷闲去Stack Overflow上赚声 ...

  3. 还敢随便抄?Stack Overflow上最火这段代码有Bug!

    程序员的成长之路 互联网/程序员/技术/资料共享 关注 阅读本文大概需要 7 分钟. 作者 | Andreas Lundblad 译者 | 弯月     责编 | 欧阳姝黎 出品 | CSDN(ID: ...

  4. Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?

    来自:沉默王二 在逛 Stack Overflow 的时候,发现了一些访问量像阿尔卑斯山一样高的问题,比如说这个:Java 到底是值传递还是引用传递?访问量足足有 188万+,这不得了啊!说明有很多很 ...

  5. Stack Overflow上最热门问题是什么?

    要找到Stack Overflow全时最热问题很容易,但是当前最热问题能告诉我们现在的重要话题.在本文中,你可以了解到怎么才能得到当前最热话题. 从下图的交互面板中你可以得到具体问题的答案.下面,我们 ...

  6. 向Stack Overflow上排名第一的大神Jon Skeet提问!

    Jon Skeet 谷歌软件工程师,微软资深C# MVP,拥有10余年C#项目开发经验.自2002年来,他一直是C#社区.新闻组.国际会议的活跃技术专家和Stack Overflow总排名第一的用户, ...

  7. 如何优雅地在Stack OverFlow 上进行编程问题搜索

    引子 百度上搜索编程问题还是一言难尽,有些问题实在是不适合在中文引擎下进行搜索,所以还是要学会科学上网,一个好程序员的英语一定是最好的,全世界90%的编程资源都是以英语形式展现,如果不学好一门外语,恐 ...

  8. python java web前端 net 移动开发_JavaScript超越了Java,c,python等等成为Stack Overflow上最热门的...

    Javascript 可以做什么 1. Web 前端 相信这个这个是毫无疑问的,在 Web 前端的地位目前是没有任何语言能撼动它的霸主地位. image.png 2. 后端 Nodejs Node.j ...

  9. Stack Overflow 上人气爆表的10个 Java 问题

    2019独角兽企业重金招聘Python工程师标准>>> 1. 为什么两个(1927年)时间相减得到一个奇怪的结果? (3623个赞) 如果执行下面的程序,程序解析两个间隔1秒的日期字 ...

最新文章

  1. oracle rodo 查看大小,Checkpoint not complete故障
  2. python实现洗牌算法_洗牌算法及 random 中 shuffle 方法和 sample 方法浅析
  3. SAP QM 事务代码QA11里的to New Material
  4. 【Flutter】Flutter 开源项目参考
  5. android websocket封装,Android WebSocket 方案选型OkHttp
  6. 第 18 章 Policy
  7. vue+node全栈移动商城【6】-node接口配置文件
  8. Andriod广播注册接收过程简析
  9. 资源 | 没有数学和编程基础,这几个数据科学项目了解一下
  10. 操作系统定义、功能、特征、分类介绍
  11. 产业研发用地_金阊新城控制规划调整 新增学校 住宅及产业研发用地
  12. php是单进程语言,但是也有办法支持多进程
  13. 谷歌翻译 翻译文档爬虫
  14. css图片九宫格布局
  15. 关于使用Python——写模拟手机通讯录查询系统
  16. 折弯机使用说明书_折弯机使用操作方法-几大要点
  17. mysql 切分_Mysql字符串切分
  18. 基于Android的手机点名签到学生请假考勤系统
  19. 一个非常适合IT团队的在线API文档、技术文档工具
  20. 电力电子系统的保护设计

热门文章

  1. hibernate 查询mysql报错Zero date value prohibited与解决
  2. Python 实现日志监控
  3. 解决.msi打不开问题
  4. csv导入mysql中文乱码等问题
  5. hangye5:09年做行业网址导航不如做行业网站联盟
  6. oracle X表汇总
  7. 什么是GC root ,GC root原理
  8. 2012年02月12日
  9. 设计平面坐标点类,计算两点之间距离、到原点距离、关于坐标轴和原点的对称点等
  10. 汽车早讯丨庞大集团董事长回应高管降薪;一嗨租车达成新私有化协议