问题
In this example code a NullPointerException
is being thrown on line 4.
1. private <O,T> void generate(Suggestion suggestion, GeneratorFactory<O, T> generatorFactory) {
2. final Generator<O, T> generator = generatorFactory.getGenerator(suggestion);
3. while (generator.hasNext()) {
4. generator.doGenerate();
5. }
6. // post-generate stuff here
7. }
It only happens occasionally, but it has happened a few times on a live server, so it's not some kind of "ghost" bug - it definitely needs fixing.
Stack trace:
java.lang.NullPointerException
at package.SuggestionServiceImpl.generate(SuggestionServiceImpl.java:4)
Code for GeneratoryFactory:
@Override
public synchronized Generator<O, T> getGenerator(final Suggestion suggestion) {
Generator<O, T> generator = generators.get(suggestion.getId());
if (generator == null) {
generator = construct(suggestion); // calls `new Generator()`
generators.put(suggestion.getId(), generator);
}
return generator;
}
I'm confused by:
- How come we don't get a NPE in the 'if' statement on line 3, if it's
generator
that's null? - How come the stack trace starts at line 4, and not from a line inside
doGenerate()
if that's where the exception is coming from? (The internals ofdoGenerate()
are lengthy and complex - it is possible that an NPE starts here, but why no stack trace?)
Update:
As an experimental test, I deliberately threw a NPE inside doGenerate()
[in dev environment] to compare the stack trace with the mystery live one. It does indeed have the anticipated extra stack frame.
java.lang.NullPointerException: DELIBERATE TEST EXCEPTION
at package.Generator.doGenerate(Generator.java:71)
at package.SuggestionServiceImpl.generate(SuggestionServiceImpl.java:4)
The runtime JVM is:
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Oracle JRockit(R) (build R28.1.4-7-144370-1.6.0_26-20110617-2130-linux-x86_64, compiled mode)
回答1:
I'll give you some theoretical options:
- it may be a mundane thing like a wrong line number reported. For example, due to different versions of binary code and the source code you are looking at;
- the exception may be happening somewhere else, but you see a severed stacktrace. This could be due to some intervenening code messing with the stacktrace (no magic neededed for this, just plain Java), or the logging framework may be messing it up occasionally;
- you are hitting an actual bug in JRockit, possibly its JIT. For example, there may be some locals clearing in effect which happens out of order.
My suggestion: insert a log statement within the loop, but above the doGenerate
call. You may also explicitly log the result of generator != null
. This will help you eliminate any but the most bizarre explanation.
回答2:
I have encountered similar issue. It looks like JUnit (or JVM) truncated stacktrace in wrong way. Wrapping whole test method in try/catch and using Exception.printStackTrace() showed the real source of NPE instead of "impossible" location.
来源:https://stackoverflow.com/questions/16913295/impossible-npe-being-thrown-java