没有 StackTrace 的 Java 中的 NullPointerException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2411487/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:15:53  来源:igfitidea点击:

NullPointerException in Java with no StackTrace

javanullpointerexception

提问by Edward Shtern

I've had instances of our Java code catch a NullPointerException, but when I try to log the StackTrace (which basically ends up calling Throwable.printStackTrace()), all I get is:

我有我们的 Java 代码实例 catch a NullPointerException,但是当我尝试记录 StackTrace(基本上最终调用Throwable.printStackTrace())时,我得到的只是:

java.lang.NullPointerException

Has anyone else come across this? I tried googling for "java null pointer empty stack trace" but didn't come across anything like this.

有没有其他人遇到过这个?我尝试在谷歌上搜索“java 空指针空堆栈跟踪”,但没有遇到类似的问题。

采纳答案by Roland Illig

You are probably using the HotSpot JVM (originally by Sun Microsystems, later bought by Oracle, part of the OpenJDK), which performs a lot of optimization. To get the stack traces back, you need to pass the option -XX:-OmitStackTraceInFastThrowto the JVM.

您可能正在使用 HotSpot JVM(最初由 Sun Microsystems,后来被 Oracle 收购,是 OpenJDK 的一部分),它执行了很多优化。要返回堆栈跟踪,您需要将选项传递-XX:-OmitStackTraceInFastThrow给 JVM。

The optimization is that when an exception (typically a NullPointerException) occurs for the first time, the full stack trace is printed and the JVM remembers the stack trace (or maybe just the location of the code). When that exception occurs often enough, the stack trace is not printed anymore, both to achieve better performance and not to flood the log with identical stack traces.

优化是当第一次发生异常(通常是 NullPointerException)时,会打印完整的堆栈跟踪,JVM 会记住堆栈跟踪(或者可能只是代码的位置)。当异常发生的频率足够高时,不再打印堆栈跟踪,以实现更好的性能并且不会用相同的堆栈跟踪淹没日志。

To see how this is implemented in the HotSpot JVM, grab a copy of itand search for the global variable OmitStackTraceInFastThrow. Last time I looked at the code (in 2019), it was in the file graphKit.cpp.

要了解这是如何在 HotSpot JVM 中实现的,请获取它的副本并搜索全局变量OmitStackTraceInFastThrow。上次我查看代码时(2019 年),它在文件graphKit.cpp 中

回答by Peter Lang

exception.toStringdoes not give you the StackTrace, it only returns

exception.toString不给你 StackTrace,它只返回

a short description of this throwable. The result is the concatenation of:

* the name of the class of this object
* ": " (a colon and a space)
* the result of invoking this object's getLocalizedMessage() method

对这个 throwable 的简短描述。结果是:

* the name of the class of this object
* ": " (a colon and a space)
* the result of invoking this object's getLocalizedMessage() method


Use exception.printStackTraceinstead to output the StackTrace.

exception.printStackTrace改为使用输出 StackTrace。

回答by Sheldon Young

toString()only returns the exception name and the optional message. I would suggest calling

toString()只返回异常名称和可选消息。我建议打电话

exception.printStackTrace()

to dump the message, or if you need the gory details:

转储消息,或者如果您需要血腥的详细信息:

 StackTraceElement[] trace = exception.getStackTrace()

回答by Michael D. Irizarry

This will output the Exception, use only to debug you should handle you exceptions better.

这将输出异常,仅用于调试您应该更好地处理您的异常。

import java.io.PrintWriter;
import java.io.StringWriter;
    public static String getStackTrace(Throwable t)
    {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        t.printStackTrace(pw);
        pw.flush();
        sw.flush();
        return sw.toString();
    }

回答by Steven Schlansker

As you mentioned in a comment, you're using log4j. I discovered (inadvertently) a place where I had written

正如您在评论中提到的,您正在使用 log4j。我(无意中)发现了一个我写过的地方

LOG.error(exc);

instead of the typical

而不是典型的

LOG.error("Some informative message", e);

through laziness or perhaps just not thinking about it. The unfortunate part of this is that it doesn't behave as you expect. The logger API actually takes Object as the first argument, not a string - and then it calls toString() on the argument. So instead of getting the nice pretty stack trace, it just prints out the toString - which in the case of NPE is pretty useless.

通过懒惰或者可能只是没有考虑它。不幸的是,它的行为并不像您期望的那样。记录器 API 实际上将 Object 作为第一个参数,而不是字符串 - 然后它在参数上调用 toString() 。因此,它没有获得漂亮的堆栈跟踪,而是打印出 toString - 这在 NPE 的情况下是非常无用的。

Perhaps this is what you're experiencing?

也许这就是你正在经历的?

回答by Steven Schlansker

Alternate suggestion - if you're using Eclipse, you could set a breakpoint on NullPointerException itself (in the Debug perspective, go to the "Breakpoints" tab and click on the little icon that has a ! in it)

替代建议 - 如果您使用的是 Eclipse,则可以在 NullPointerException 本身上设置断点(在 Debug 透视图中,转到“Breakpoints”选项卡并单击其中带有 ! 的小图标)

Check both the "caught" and "uncaught" options - now when you trigger the NPE, you'll immediately breakpoint and you can then step through and see how exactly it is handled and why you're not getting a stack trace.

检查“捕获”和“未捕获”选项 - 现在当您触发 NPE 时,您将立即断点,然后您可以逐步查看它是如何处理的以及为什么没有获得堆栈跟踪。

回答by Stephen C

(Your question is still unclear on whether your code is calling printStackTrace()or this is being done by a logging handler.)

(您的问题仍然不清楚您的代码是在调用printStackTrace()还是由日志处理程序完成。)

Here are some possible explanations about what might be happening:

以下是对可能发生的事情的一些可能的解释:

  • The logger / handler being used has been configured to only output the exception's message string, not a full stack trace.

  • Your application (or some third-party library) is logging the exception using LOG.error(ex);rather than the 2-argument form of (for example) the log4j Logger method.

  • The message is coming from somewhere different to where you think it is; e.g. it is actually coming some third-party library method, or some random stuff left over from earlier attempts to debug.

  • The exception that is being logged has overloaded some methods to obscure the stacktrace. If that is the case, the exception won't be a genuine NullPointerException, but will be some custom subtype of NPE or even some unconnected exception.

  • 正在使用的记录器/处理程序已配置为仅输出异常的消息字符串,而不是完整的堆栈跟踪。

  • 您的应用程序(或某些第三方库)正在使用LOG.error(ex);log4j Logger 方法而不是(例如)的 2 参数形式记录异常。

  • 消息来自与您认为的不同的地方;例如,它实际上来自一些第三方库方法,或者一些早期尝试调试遗留下来的随机内容。

  • 正在记录的异常重载了一些方法来掩盖堆栈跟踪。如果是这种情况,异常将不是真正的 NullPointerException,而是 NPE 的一些自定义子类型,甚至一些未连接的异常。

I think that the last possible explanation is pretty unlikely, but people do at least contemplate doing this kind of thing to "prevent" reverse engineering. Of course it only really succeeds in making life difficult for honest developers.

我认为最后一种可能的解释不太可能,但人们至少考虑做这种事情来“防止”逆向工程。当然,它只会真正成功地让诚实的开发人员生活变得困难。

回答by Matt Solnit

We have seen this same behavior in the past. It turned out that, for some crazy reason, if a NullPointerException occurred at the same place in the code multiple times, after a while using Log.error(String, Throwable)would stop including full stack traces.

我们过去曾见过这种行为。事实证明,出于某种疯狂的原因,如果 NullPointerException 多次出现在代码中的同一位置,一段时间后 usingLog.error(String, Throwable)将停止包括完整的堆栈跟踪。

Try looking further back in your log. You may find the culprit.

尝试进一步查看您的日志。你可能会找到罪魁祸首。

EDIT:this bugsounds relevant, but it was fixed so long ago it's probably not the cause.

编辑:这个错误听起来很相关,但它很久以前就被修复了,这可能不是原因。

回答by Beno?t Guérout

Here is an explanation : Hotspot caused exceptions to lose their stack traces in production – and the fix

这是一个解释:热点导致异常在生产中丢失其堆栈跟踪 - 以及修复

I've tested it on Mac OS X

我已经在 Mac OS X 上测试过了

  • java version "1.6.0_26"
  • Java(TM) SE Runtime Environment (build 1.6.0_26-b03-383-11A511)
  • Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02-383, mixed mode)

    Object string = "abcd";
    int i = 0;
    while (i < 12289) {
        i++;
        try {
            Integer a = (Integer) string;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
  • java版本“1.6.0_26”
  • Java(TM) SE 运行时环境(构建 1.6.0_26-b03-383-11A511)
  • Java HotSpot(TM) 64 位服务器 VM(构建 20.1-b02-383,混合模式)

    Object string = "abcd";
    int i = 0;
    while (i < 12289) {
        i++;
        try {
            Integer a = (Integer) string;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

For this specific fragment of code, 12288 iterations (+frequency?) seems to be the limit where JVM has decided to use preallocated exception...

对于这个特定的代码片段,12288 次迭代(+频率?)似乎是 JVM 决定使用预分配异常的限制......

回答by Roland Illig

When you are using AspectJ in your project, it may happen that some aspect hides its portion of the stack trace. For example, today I had:

当您在项目中使用 AspectJ 时,可能会发生某些方面隐藏其堆栈跟踪部分的情况。例如,今天我有:

java.lang.NullPointerException:
  at com.company.product.MyTest.test(MyTest.java:37)

This stack trace was printed when running the test via Maven's surefire.

此堆栈跟踪是在通过 Maven 的 surefire 运行测试时打印的。

On the other hand, when running the test in IntelliJ, a different stack trace was printed:

另一方面,在 IntelliJ 中运行测试时,打印了不同的堆栈跟踪:

java.lang.NullPointerException
  at com.company.product.library.ArgumentChecker.nonNull(ArgumentChecker.java:67)
  at ...
  at com.company.product.aspects.CheckArgumentsAspect.wrap(CheckArgumentsAspect.java:82)
  at ...
  at com.company.product.MyTest.test(MyTest.java:37)