抛出Null Pointer Exception时如何查找null对象

时间:2014-08-26 08:21:58

标签: java

当抛出NullPointerException时,java中是否有任何方法可以知道违规对象的Class的名称?当有问题的java语句有很多可以为null的对象时,这将有助于调试代码。

4 个答案:

答案 0 :(得分:3)

看看这段代码和评论:

public class Main {

    public static void main(final String args[])
    {
        Main test = new Main();
        test.testNull();
        System.out.println("My program still works!");  //this WILL NOT be printed asn NPE is thrown in testNull() and it's not caught - this will result in stopping the program.
    }

    private void testNull()
    {
        String aaa = null;
        aaa.charAt(1); //here you'll get a NullPointerException because there 'aaa' doesn't reference any existing object.
    }
}

输出将是这样的:

Exception in thread "main" java.lang.NullPointerException  //error caught in method "main", you also have the exception class shown.
    at Main.testNull(Main.java:26)  //null was found in file Main.java in method testNull on line 26.
    at Main.main(Main.java:19)      //the method testNull was called from method main - line 19.

修改 你可以这样做:

public static void main(final String args[])
{
    Main test = new Main();
    try
    {
        test.testNull();
    }
    catch (final NullPointerException e) //catch the NPE
    {
        e.printStackTrace();             //print info about the cause.
        //do some other stuff to handle the exception
    }
    System.out.println("My program still works!");  //this WILL be printed
}

输出:

java.lang.NullPointerException
    at Main.testNull(Main.java:25)
    at Main.main(Main.java:13)
My program still works!

答案 1 :(得分:1)

试图解开你的一些措辞:

对象永远不会是null!它是一个可以null的引用。引用有一个类型 - 要么是声明的变量,要么是更复杂的表达式(例如方法调用)。

当您尝试取消引用NullPointerException的引用时会发生null,这仅表示引用指向对象。没有机会获取不存在的对象的类。我想,你想在NPE的情况下检索引用null的表达式的类型,不是吗?

唯一可以获得(并且应该分析)的是NPE发生的源代码行。这是异常堆栈跟踪的一部分。有了这些信息,您就可以调试代码。

答案 2 :(得分:0)

不幸的是没有。

您的意思是声明类型的值。它仅在Compile-Time(通常向IDE报告)中提供。

编译成字节码后,声明信息被删除,因此即使int也可以包含String。这就是方法签名非常重要的原因!

答案 3 :(得分:0)

添加到Seelenvirtuose的答案:

如果要查明导致NullPointerException的确切原因,请首先在堆栈跟踪中找到引发异常的行。这通常是追踪中的顶线。

让我们说这就是这条线:

vfoo = foo.ffoo(bar.fbar(),foo2);

这里可能的罪犯是foo或bar。 vfoo不能抛出异常,因为它没有被解除引用,与foo 2相同。它不能在函数foo.ffoo()或bar.fbar()中,因为那时堆栈跟踪不会#39 ; t指向此行,但会在这些函数中显示异常。因此,剩下的一切都是foo和bar,因为它们都被解除引用。 因此,要找出它们中的哪一个,只需将语句分开:

temp = bar.fbar();
vfoo = foo.ffoo(temp,foo2);

现在堆栈跟踪将指向一行或另一行,您将知道bar或foo为null。

你也可以在声明之前做这样的事情:

System.out.println("bar exists: "+(bar!=null));
System.out.println("foo exists: "+(foo!=null));

最后一点要谈谈:变量何时被解除引用?

只有对象可以被解引用,所以像int,float,double,char,byte等原语既不能为空也不能被解除引用。 使用时,对象被取消引用。运算符访问对象的字段或函数(例如foo.bar()或foo.ibar = 5)。当你使用支持自动装箱的对象(例如Integer,Float,Double,Char,...)并使用任何数学或逻辑运算符(例如+, - ,*,/,&,&)时,它也会被取消引用。 &,|,||,!)。它基本上是每次您尝试访问对象的内容而不仅仅是对它的引用。