`
jeff.chuh
  • 浏览: 2782 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

可恶的NullPointerException与JVM的失职

阅读更多
由于程序的不严密而出现NullPointerException异常的代码太常见了,
虽然可以在使用对象前检查是否为空,但过多的这种检查会使代码臃肿。
出现这样的异常的时候常常没有明确的信息,给调试带来不便,
即使知道抛出异常的代码行号,但或许因为你手头没有代码,或许因为这行代码有多次方法调用,
而很难得到错误的原因或是判断究竟什么对象是空。

我觉得这是JVM的失职,它只是抛出了没有任何信息的NullPointerException,
为什么不追加“调用XXX方法时,发现对象不可用”的信息呢
分享到:
评论
44 楼 jeff.chuh 2008-11-20  
不是抱怨,是希望
43 楼 wangzaixiang 2008-11-20  
是有些道理。不过,不用升级到这么严重的抱怨啊。
42 楼 gembler 2008-11-20  
jeff.chuh 写道
gembler 写道
jeff.chuh 写道
gembler 写道
jeff.chuh 写道

我觉得这是JVM的失职,它只是抛出了没有任何信息的NullPointerException,
为什么不追加“调用XXX方法时,发现对象不可用”的信息呢


异常堆栈里已经明确指出了。`````不知道LZ是用什么样的格式写error log的


堆栈只能给出XX方法执行到第几行出异常了,
而不能指出执行那行代码的时候,是调用了什么对象的什么方法



对于obj.getA().getB().getC()这样一种的典型代码结构没法定位到底是obj还是getA()还是getB()出现null,是没错,不过见到这样的代码结构难道你就不重构一下了吗?如果真的写出这种结构的代码,我觉得主要责任还是在写这段代码的人,尽管vm有一点点责任。


说的没错,就怕这样的代码出现在一些框架或者一些产品里


成熟的框架,源码里有这样的结构的代码还是少见。
如果是开发人员的问题,那就应该事前弄一套编码规范来培训培训,如果没来得及搞培训只好乖乖地重构了。
41 楼 gembler 2008-11-20  
LZ你这个话题有悬点,因为大家都认为不应该出现下面的代码结构:

obj.getA().getB().getC()

而大家都是认为下面代码结构才对:

Object objA = obj.getA();
Object objB = obj.getB();
Object objC = obj.getC();

所以,基本上是绕了一个圈。
40 楼 jeff.chuh 2008-11-20  
gembler 写道
jeff.chuh 写道
gembler 写道
jeff.chuh 写道

我觉得这是JVM的失职,它只是抛出了没有任何信息的NullPointerException,
为什么不追加“调用XXX方法时,发现对象不可用”的信息呢


异常堆栈里已经明确指出了。`````不知道LZ是用什么样的格式写error log的


堆栈只能给出XX方法执行到第几行出异常了,
而不能指出执行那行代码的时候,是调用了什么对象的什么方法



对于obj.getA().getB().getC()这样一种的典型代码结构没法定位到底是obj还是getA()还是getB()出现null,是没错,不过见到这样的代码结构难道你就不重构一下了吗?如果真的写出这种结构的代码,我觉得主要责任还是在写这段代码的人,尽管vm有一点点责任。


说的没错,就怕这样的代码出现在一些框架或者一些产品里
39 楼 gembler 2008-11-20  
jeff.chuh 写道
gembler 写道
jeff.chuh 写道

我觉得这是JVM的失职,它只是抛出了没有任何信息的NullPointerException,
为什么不追加“调用XXX方法时,发现对象不可用”的信息呢


异常堆栈里已经明确指出了。`````不知道LZ是用什么样的格式写error log的


堆栈只能给出XX方法执行到第几行出异常了,
而不能指出执行那行代码的时候,是调用了什么对象的什么方法



对于obj.getA().getB().getC()这样一种的典型代码结构没法定位到底是obj还是getA()还是getB()出现null,是没错,不过见到这样的代码结构难道你就不重构一下了吗?如果真的写出这种结构的代码,我觉得主要责任还是在写这段代码的人,尽管vm有一点点责任。
38 楼 jeff.chuh 2008-11-20  
你这样写的代码会很健壮,我现在也是尽量这么做的,但是大项目中往往控制不了别人怎么写代码。
37 楼 niyanshi 2008-11-20  
jeff.chuh 写道
niyanshi 写道
我的经验,不是在使用对象的时候再判断,而是在自己的类的构造方法或setter里就判断。比如
Class A{
    public A(String s1, Object o){
       if (s1 == null){
           Throw new NullPointerException("s1 should not be null");
       }
       if (o == null){
           Throw new NullPointerException("o should not be null");
       }
    }
}
这样的好处是调试时候可以及早发现哪个不该为null的对象是null了。而不是等这个null被一层层传下去到了那些没代码的包里时再抛上来。另外在逻辑代码里面也不需要再写if (xx==null) //do something这样讨厌的东西。


但是如果ClassA的实例是null呢,那你调用它的方法也是会出错的,
构造方法只能保证对象的成员被合理初期化了,而不能保证对象自身。

Class A的实例也是在别的方法被调用到的嘛。在一个要用到class A的接口/方法里,也会先对class A进行判断。我的原则就是,我所开发的组件的接口方法中,一定会对传进来的参数先做检查。这样就可以尽早发现NullPointerException,IllegalArgumentException之类的错误是在什么地方发生的。
36 楼 jeff.chuh 2008-11-20  
Scriptlet 写道
lz这个问题太白了。
如果是obj.getAAA().getBBB().getCCC()这行出错,那么obj一定是null,否则问题肯定处在getAAA或者getBBB, getCCC的内部-就不是这一行了。
看看完整的stacktrace就会定位出来:如果getCCC出错,那么第一个出错的行号肯定在getCCC内,然后才是getBBB以及getAAA。
我也怀疑你到底用过JAVA没有 


真是这样吗!自己做个简单的实验再和我说,
为什么一定是obj为null呢,obj.getAAA()的返回值为null的话就不可以吗
35 楼 jeff.chuh 2008-11-20  
niyanshi 写道
我的经验,不是在使用对象的时候再判断,而是在自己的类的构造方法或setter里就判断。比如
Class A{
    public A(String s1, Object o){
       if (s1 == null){
           Throw new NullPointerException("s1 should not be null");
       }
       if (o == null){
           Throw new NullPointerException("o should not be null");
       }
    }
}
这样的好处是调试时候可以及早发现哪个不该为null的对象是null了。而不是等这个null被一层层传下去到了那些没代码的包里时再抛上来。另外在逻辑代码里面也不需要再写if (xx==null) //do something这样讨厌的东西。


但是如果ClassA的实例是null呢,那你调用它的方法也是会出错的,
构造方法只能保证对象的成员被合理初期化了,而不能保证对象自身。
34 楼 jeff.chuh 2008-11-20  
xieke 写道
obj.getAAA().getBBB().getCCC().getDDD().........getZZZ()......get火星java()......
这都完全没有问题啊,都能打印调用栈
很奇怪这帖子还没被置为新手贴


真是这样吗?
堆栈显示这行抛出NullPointerException,
那你能具体知道是obj为null,还是obj.getAAA()返回null,或者obj.getAAA().getBBB()返回null
先回答这个问题,再说别人
33 楼 jeff.chuh 2008-11-20  
aws 写道
jeff.chuh 写道
引用
还是不太理解你的问题。
NullpointerException
堆栈中肯定包含了对应的对应方法调用信息的啊。。。最后会深入到哪一行的啊。虽然jsp这样的没法调试,但写java代码行标识还是很准确的吧。。


如果那行代码是obj.getAAA().getBBB().getCCC()你就不知道具体是哪个出问题了吧


会抛出异常
我说你到底有没有用过java啊?


说别人前好好把自己的中文组织一下,
并且自己动手试一试
32 楼 jeff.chuh 2008-11-20  
wilsonxu 写道
就算是getA().getB().getC()的语句,异常栈也可以清晰指出具体抛出异常的方法。


自己试一试才会有正确的答案
31 楼 jeff.chuh 2008-11-20  
baseworld 写道
可以参考guice里面对错误信息的处理方式


能给个例子吗,对于guice还只是浅浅接触过
30 楼 jeff.chuh 2008-11-20  
ray_linn 写道
design by contrat,这样的工具多了去了。


iContract还是JML,他们都有自己特定的编译器吧,
然后来解释一些注释模样的契约,
不知道编译的质量能不能保证,能不能跟得上jdk的版本升级,
其实最简单的解决是JVM自身不是吗,
那样我们不用费力去写契约
29 楼 Scriptlet 2008-11-20  
lz这个问题太白了。
如果是obj.getAAA().getBBB().getCCC()这行出错,那么obj一定是null,否则问题肯定处在getAAA或者getBBB, getCCC的内部-就不是这一行了。
看看完整的stacktrace就会定位出来:如果getCCC出错,那么第一个出错的行号肯定在getCCC内,然后才是getBBB以及getAAA。
我也怀疑你到底用过JAVA没有 
28 楼 jeff.chuh 2008-11-20  
gembler 写道
jeff.chuh 写道

我觉得这是JVM的失职,它只是抛出了没有任何信息的NullPointerException,
为什么不追加“调用XXX方法时,发现对象不可用”的信息呢


异常堆栈里已经明确指出了。`````不知道LZ是用什么样的格式写error log的


堆栈只能给出XX方法执行到第几行出异常了,
而不能指出执行那行代码的时候,是调用了什么对象的什么方法
27 楼 jeff.chuh 2008-11-20  
hocus 写道
jeff.chuh 写道
由于程序的不严密而出现NullPointerException异常的代码太常见了

1 你为啥不提高对自己的要求,让代码严密些呢
2 单元测试就是为此而生的
3 jvm给了你异常处理,还有客制化这些信息的自由


使代码严密当然好,但是程序员大多都达不到;
有些代码是在特殊情况下才发生
NullPointerException,比如反序列化失败,单体测试也不行吧;
我只是认为JVM给的信息有点少,在多点方便调试。
26 楼 jeff.chuh 2008-11-20  
javaeyebird 写道
jeff.chuh 写道
由于程序的不严密而出现NullPointerException异常的代码太常见了,
虽然可以在使用对象前检查是否为空,但过多的这种检查会使代码臃肿。
出现这样的异常的时候常常没有明确的信息,给调试带来不便,
即使知道抛出异常的代码行号,但或许因为你手头没有代码,或许因为这行代码有多次方法调用,
而很难得到错误的原因或是判断究竟什么对象是空。

我觉得这是JVM的失职,它只是抛出了没有任何信息的
NullPointerException,
为什么不追加“调用XXX方法时,发现对象不可用”的信息呢

为什么必须要单独给NullPointerException加上“调用XXX时”呢?其他的Exception不需要加么?
因为从stack trace中就能得到方法调用的信息
try { ... } catch (Exception e) {
  log.debug(e); // 或者简单地e.printStackTrace()
}



只能得到某个方法执行到第几行的时候出现了NullPointerException,
而不知道那行代码究竟是什么,比如执行XX对象的XX方法这样的信息没有。
25 楼 niyanshi 2008-11-20  
我的经验,不是在使用对象的时候再判断,而是在自己的类的构造方法或setter里就判断。比如
Class A{
    public A(String s1, Object o){
       if (s1 == null){
           Throw new NullPointerException("s1 should not be null");
       }
       if (o == null){
           Throw new NullPointerException("o should not be null");
       }
    }
}
这样的好处是调试时候可以及早发现哪个不该为null的对象是null了。而不是等这个null被一层层传下去到了那些没代码的包里时再抛上来。另外在逻辑代码里面也不需要再写if (xx==null) //do something这样讨厌的东西。

相关推荐

    推荐一些JVM原理,JVM调优,JVM内存模型,JAVA并发 电子书1

    标题中提到了JVM原理、JVM调优、JVM内存模型和JAVA并发,这些都是Java虚拟机(JVM)相关的核心概念。JVM是运行Java字节码的虚拟计算机,为Java提供了一个跨平台的环境,确保Java程序可以在不同的操作系统上运行而...

    深入JVM内核—原理、诊断与优化

    《深入JVM内核—原理、诊断与优化》是一份深度探索Java虚拟机(JVM)的视频教程,旨在帮助开发者全面理解JVM的工作机制,掌握性能诊断技巧,并能进行有效的优化。本教程覆盖了从基础到高级的JVM主题,不仅适用于Java...

    jdk,jvm源码

    Java虚拟机(JVM)是Java程序运行的核心,它负责解释和执行字节码,为Java应用程序提供了一个跨平台的运行环境。...通过结合理论知识与实际源码阅读,可以更好地掌握Java编程的精髓,提高解决复杂问题的能力。

    Linux简单调优与JVM参数.docx

    Linux 服务器调优与 JVM 参数调优 本文主要介绍了 Linux 服务器调优和 JVM 参数调优的相关知识点,以便提高服务器性能和 JVM 应用程序的运行效率。 Linux 服务器调优 Linux 服务器调优是指对 Linux 操作系统的...

    揭秘Java虚拟机-JVM设计原理与实现

    《揭秘Java虚拟机-JVM设计原理与实现》这本书深入探讨了Java虚拟机(JVM)的工作原理及其在Java编程中的核心地位。Java虚拟机是Java平台的核心组成部分,它负责执行字节码,为开发者提供了跨平台的运行环境。以下是...

    深入JVM内核—原理、诊断与优化视频教程-3.常用JVM配置参数

    本教程——“深入JVM内核—原理、诊断与优化视频教程”,将重点讲解这些关键点,帮助开发者提升技术水平,更好地解决实际问题。 首先,我们来探讨JVM的内核原理。JVM主要由类加载子系统、运行时数据区、执行引擎、...

    (46页完整版)JVM体系结构与GC调优.zip

    46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT详解JVM,46页PPT...

    JVM与GC调优课程视频

    JVM与GC调优课程视频 〖课程介绍〗: JVM与GC调优课程视频 〖课程目录〗: 1.笔记/ ├── 第1篇-字节码篇.png?x-oss-process=style/pnp8 ├── 第2篇-类的加载篇.png?x-oss-process=style/pnp8 ├── 第3篇-运行时...

    深入JVM内核—原理、诊断与优化视频教程-2.JVM运行机制

    【JVM运行机制详解】 Java虚拟机(JVM)是Java平台的核心组成部分,它负责执行...在《深入JVM内核—原理、诊断与优化》视频教程中,会详细讲解这些内容,并结合实际案例进行演示和实践,帮助开发者成为JVM领域的专家。

    jvm 详细介绍,了解jvm各个组成部分和功能

    ### JVM 详细介绍:掌握 JVM 的各个组成部分与功能 #### 一、Java 源文件编译及执行 Java 应用程序的核心在于源文件的编译与执行。不同于 C/C++ 这类需要针对不同平台进行编译的语言,Java 采用了一种更为灵活的...

    JVM详解与学习

    ### JVM详解与学习 #### Java相关 ##### 1.1 Java定义 Java 是一种广泛使用的高级编程语言,具有面向对象、跨平台等特性。它的设计理念是“一次编写,到处运行”,这得益于Java虚拟机(JVM)的存在。JVM使得Java...

    jvm 启动过程 JVM 原理

    - **本地方法栈**:与Java方法不同,本地方法栈为JNI(Java Native Interface)调用的C/C++等本地方法服务。 了解JVM的启动过程和工作原理对于优化Java程序性能至关重要。通过调整JVM参数,我们可以控制堆大小、...

    gp-jvm-visualvm

    《深入探索Java虚拟机:以gp-jvm-visualvm为例》 Java虚拟机(JVM)是Java程序运行的核心,它负责解析字节码、管理内存、执行线程以及优化代码。当我们谈论“gp-jvm-visualvm”时,我们是在讨论一个用于深入理解和...

    jvm特性与java特性

    Android最初使用Dalvik虚拟机来执行Android应用程序,虽然Dalvik与传统的JVM在设计上有所不同,但随着Android的发展,现在主流Android应用也是基于Java或Kotlin开发,并且在Android Runtime (ART)下运行,ART替代了...

    JVM规范与深入理解

    《JVM规范与深入理解》这个主题涵盖了Java虚拟机(Java Virtual Machine)的全面解析,旨在帮助开发者深入了解JVM的工作原理及其对程序性能的影响。在这个主题中,我们主要关注两个核心资源:周志明的《深入理解Java...

    JVM图解-JVM指令-JVM原型图.rar

    在这个压缩包中,"JVM图解.png"可能是对JVM内部结构的可视化表示,"JVM图解"可能是一个详细的文档,解释了JVM的工作原理,而"JVM指令手册 中文版"则提供了JVM可执行的所有指令的详细信息。下面,我们将深入探讨JVM的...

    狂神说JVM探究.rar

    - 本地方法栈:与JVM栈类似,但服务于Java Native Interface(JNI)调用的本地方法。 - 堆内存:存放对象实例,进行垃圾回收的主要区域。 - 方法区(非堆):存储已加载的类信息、常量、静态变量等。 - 运行时...

    SAP JVM 8.1 64 bits

    SAP JVM旨在提高性能、可靠性和安全性,同时确保与SAP产品的无缝集成。以下是对这个版本的一些关键知识点的详细解释: 1. **64位架构**:SAP JVM 8.1是针对64位操作系统设计的,这意味着它可以利用更多的内存资源,...

    JVM中文指令手册.pdf

    6. 参数与执行:一部分JVM指令需要一个参数来指示需要执行的操作,例如push指令。参数通常紧跟在指令码之后,明确指出指令要操作的具体内容。 7. 缺失信息的处理:文档提到了由于OCR扫描导致的识别错误或者漏识别...

Global site tag (gtag.js) - Google Analytics