如何诊断哪个字段/方法导致了 NullPointerException

发布于 2024-11-25 12:46:37 字数 327 浏览 1 评论 0原文

假设您的 Java 代码如下所示:

getPerson().getParent().getSiblings().first().getName()

您在该行上得到一个 NullPointerException。你如何找出哪一个为空?您可以调试它并检查每个调用,或者您可以暂时将链接拆分为多行。

然而,我记得不久前看到一个开源项目,我认为它可以作为 javaagent 运行,这将为您提供更好的 NullPointerException 堆栈跟踪,其中它提供了返回 null 结果的方法调用。不幸的是我似乎找不到它。有谁知道如何做到这一点,或者它是什么工具?

Let's say you have Java code that looks like:

getPerson().getParent().getSiblings().first().getName()

And you get a NullPointerException on that line. How do you figure out which one was null? You can debug it and check every call, or you can temporarily split the chaining in to multiple lines.

However, I remember seeing an open source project a while ago which would run, I think as a javaagent, which would give you a better stack trace for a NullPointerException where it gave the method call that returned the null result. Unfortunately I can't seem to find it. Does anyone know how that would be done, or what tool it was?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一指流沙 2024-12-02 12:46:37

有趣的。

一个人可以有一个空的父母吗? (有性生殖的生物不是有两个父母吗?)

如果你是独生子怎么办? getSiblings() 应该返回什么? null 或者更好的是,一个空集合?

如果你没有名字怎么办?斯汀或麦当娜是名字还是姓氏?如果是第一个,姓氏返回什么?

这里真正的问题是设计。您还没有充分考虑在空值情况下该怎么办。最好弄清楚这一点。

Interesting.

Can a Person have a null Parent? (Don't sexually reproducing beings have two Parents?)

What if you're an only child? What should getSiblings() return? null or, better yet, an empty Collection?

What if you don't have a first name? Is Sting or Madonna a first or last name? If first, what does last name return?

The real issue here is design. You haven't thought enough about what to do in the case of nulls. Better to figure that out.

半边脸i 2024-12-02 12:46:37

恕我直言,当您不放入可能引发 npe 的单行方法时,这是一种更好的风格。那么你就不会遇到这样的问题了:) 即使将每个调用放在一行中(但与 method1()\n.method2() 等相同的指令)也不是一个好主意。简单的代码重新格式化可以将它们放回一行。

如果方法可能返回 null,那么您应该每次都检查返回值。如果该方法不应返回 null,则 getter 应包含检查并抛出异常(IllegalStateException?)而不是返回 null。

您可以向现有代码添加这样的检查:使用 AspectJ 和加载时 veave(使用 javaagent)。

例如:

/** Throw Error if a method for creating a Point returns null */
after () returning (Point p) : 
    call(Point+ SubPoint+.create(..)) {
    if (null == p) {
        String err = "Null Point constructed when this (" 
            + thisJoinPoint.getThis() 
            + ") called target (" 
            + thisJoinPoint.getTarget() 
            + ") at join point (" 
            + thisJoinPoint.getSignature() 
            + ") from source location (" 
            + thisJoinPoint.getSourceLocation()
            + ") with args ("
            + Arrays.asList(thisJoinPoint.getArgs())
            + ")";
        throw new Error(err);
    }
}

IMHO it is a better style when you don't put in one line methods which may throw npe. Then you don't have such a problem :) Even putting each invocation in a single line (but the same instruction like method1()\n.method2() and so one) is not a good idea. Simple code reformatting can put them back in one line.

If method may return null you should really check the return value each time. If the method should not return null, the getter should contain a check and throw an exception (IllegalStateException?) instead of returning null.

You can add to existing code such a check with AspectJ and load-time veave (using javaagent).

For example:

/** Throw Error if a method for creating a Point returns null */
after () returning (Point p) : 
    call(Point+ SubPoint+.create(..)) {
    if (null == p) {
        String err = "Null Point constructed when this (" 
            + thisJoinPoint.getThis() 
            + ") called target (" 
            + thisJoinPoint.getTarget() 
            + ") at join point (" 
            + thisJoinPoint.getSignature() 
            + ") from source location (" 
            + thisJoinPoint.getSourceLocation()
            + ") with args ("
            + Arrays.asList(thisJoinPoint.getArgs())
            + ")";
        throw new Error(err);
    }
}
你不是我要的菜∠ 2024-12-02 12:46:37

理想情况下,您可以将每个方法的返回值分配给一个变量,这样您就可以检查它们;无论如何,这就是编译器在内部对临时变量所做的事情。

如果您不想重写,可以在该行上设置一个断点,然后为每个函数添加一个监视(最简单),或者(如果您的 IDE 支持)逐个键入每个函数 -将时间放入“立即”窗口,看看会返回什么。

Ideally, you would have each method's return value assigned to a variable, so you could just inspect those; that's what the compiler does with temp variables internally anyway.

If you don't feel like re-writing, you can set a breakpoint on that line, and then either add a watch for each function (easiest), or (if your IDE supports it) type each function one-at-a-time into the "immediate" window and see what comes back.

似梦非梦 2024-12-02 12:46:37

我的观点是,这是一个简洁代码与可维护代码的问题。链接函数可能会使代码看起来更干净,但可能会导致代码库更难以长期维护。如果将操作分开,您的函数可能会更长,但追踪错误应该会容易得多。

My opinion is that this is a question of succinct code over maintainable code. Chaining functions may make the code look cleaner, but can lead to a codebase that is harder to maintain over the long haul. If you separate out your operations, you may have a longer function, but it should be significantly easier to trace down bugs.

情丝乱 2024-12-02 12:46:37

我认为有些人可能会让这比OP所要求的要复杂得多。

你所要做的就是将每个链接的方法放在自己的行上。

getPerson()
.getParent()
.getSiblings()
.first()
.getName();

您将获得正确的行号,该行号将指示 NPE 是哪个方法(前一行返回 null)。

是的,您可以进行各种强大的 NPE 检查,但最终有时您需要完成工作,而 null 可能不是预期的,所以不要用其他一些错误处理来粉饰它。

您还可以通过在对象上添加验证注释来防止这种情况发生及其子对象。验证对象,然后继续遍历对象树。过去这对我来说效果很好。这将为您提供更好的自动可重用错误处理。另外,您正在记录哪些方法可以返回 null。

说它的糟糕设计来支持链接我认为不公平,因为最流行的 Javascript (jQuery) 库之一一直使用它(是的,它有时会返回 null/未定义的值)。

I think some might be making this far more complicated than what the OP is asking for

All you have to do is put each chained method on its own line.

getPerson()
.getParent()
.getSiblings()
.first()
.getName();

And you will get the right line number which will indicate which method the NPE is (the previous line is returning null).

And yes you could do all kinds of robust NPE checking but at the end of the day sometimes you need to just get stuff done and null maybe not expected so don't sugar coat it with some other error handling.

You can also prevent this from happening by adding validation annotations on the object and its children. Validate the object and then proceed to walk the object tree. This has worked well for me in the past. This will give you better automatic reusable error handling. Plus you are documenting which methods can return null.

Saying its bad design to support chaining I don't think is fair since one of the most popular Javascript (jQuery) libraries uses it all the time (and yes it returns null/undefined values sometimes).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文