the*_*ima 5 java jvm nullpointerexception java-8 java-stream
我有以下异常(stacktrace):
java.lang.NullPointerException
at sun.reflect.GeneratedConstructorAccessor171.newInstance(Unknown Source) ~[?:?]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:1.8.0_40]
at java.lang.reflect.Constructor.newInstance(Constructor.java:422) ~[?:1.8.0_40]
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:598) ~[?:1.8.0_40]
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677) ~[?:1.8.0_40]
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735) ~[?:1.8.0_40]
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160) ~[?:1.8.0_40]
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:174) ~[?:1.8.0_40]
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233) ~[?:1.8.0_40]
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[?:1.8.0_40]
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:583) ~[?:1.8.0_40]
at com.tradair.tnet.services.trades.TradeService.updateUnrealizedPNL(TradeService.java:173) ~[tnet.jar:5.1.1.0-SNAPSHOT]
Run Code Online (Sandbox Code Playgroud)
从我TradeService班上的课程开始:
public void updateUnrealizedPNL(Set<Org> orgsToCaluclate, Set<Org> orgsToSendUpdate) {
orgsToCaluclate.parallelStream().forEach(o -> {
pnlService.updateMidPrices(o);
Collection<SystemTradeOrder> allLiveTradesByOrgId = tradesRepository.getAllLiveTradesByOrgId(o.getId());
updateUnrealizedPNL(o, allLiveTradesByOrgId);
});
// more code ....
Run Code Online (Sandbox Code Playgroud)
因此看起来在运行forEach(..)方法时抛出异常会在java本机代码中抛出.我的意思是,NullPointerException不会从我自己的代码中抛出 - 而不是从我的消费者函数中抛出,而消费函数在forEach(..)方法中作为参数出现.
我仔细检查了orgsToCaluclate这段代码运行时没有修改集合.
这是初始化 orgsToCaluclate:
Set<Org> orgsToCaluclate = getMarginOrgs();
orgsToCaluclate = orgsToCaluclate.stream()
.filter(org -> !isOrgInCloseout(org.getId())).collect(Collectors.toSet());
Run Code Online (Sandbox Code Playgroud)
有什么想法吗?..
Hol*_*ger 10
我们习惯说异常的堆栈跟踪反映了"它发生的地方",但这是一个不精确的陈述.异常的堆栈跟踪通常反映其实例的创建位置.
当我们有表格的代码时,
1 String s=null;
2 s.length();
Run Code Online (Sandbox Code Playgroud)
JRE将创建一个实例,NullPointerException当我们尝试取消引用null调用方法时length(),它的堆栈跟踪将报告行2.
但是,当我们有以下代码时
1 String s=null;
2 if(s == null) {
3 RuntimeException rt=new NullPointerException();
4 throw rt;
5 }
Run Code Online (Sandbox Code Playgroud)
堆栈跟踪不会报告检测到错误条件的位置(行2),也不报告抛出异常的位置(行4),而是在行中创建实例的位置3.
对于大多数实际案例来说,这些地方足够接近,没有显着差异,但在这里,我们有一个特殊的情况.
正如tonakai所指出的,ForkJoinTask它将通过Reflection创建一个已经遇到的异常的新实例,正如我们在源代码中看到的那样,当线程不匹配时.
当它成功时,它的堆栈跟踪将精确地反映创建新异常实例的位置,这是在执行反射实例创建的一些生成代码中.当然,这种成功的创建无法与JRE在执行相同代码时由于错误条件而创建异常的情况区分开来.
但是当我们仔细观察源代码时,我们会看到整个反射创建都附带了一个
584 try {
…
604 } catch (Exception ignore) {
605 }
Run Code Online (Sandbox Code Playgroud)
块.因此,如果操作确实失败,则不会出现任何异常.相反,代码已经倒下以返回原始异常.这表明反射代码没有失败,而是我们看到成功的,反射性创建的NullPointerException实例返回,getThrowableException()并且稍后故意抛出ForkJoinTask以报告NullPointerException在处理过程中存在另一个线程.
但是这段代码初始化了新异常的原因,指向原始异常.例如以下代码:
import java.util.stream.IntStream;
public class Main
{
public static void main(String[] args) {
Thread main=Thread.currentThread();
IntStream.range(0, 1000).parallel().forEach(i -> {
if(Thread.currentThread()!=main)
throw new NullPointerException();
});
}
}
Run Code Online (Sandbox Code Playgroud)
版画
Exception in thread "main" java.lang.NullPointerException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:598)
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)
at java.util.stream.ForEachOps$ForEachOp$OfInt.evaluateParallel(ForEachOps.java:189)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.IntPipeline.forEach(IntPipeline.java:404)
at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:560)
at Main.main(Main.java:7)
Caused by: java.lang.NullPointerException
at Main.lambda$main$0(Main.java:9)
at java.util.stream.ForEachOps$ForEachOp$OfInt.accept(ForEachOps.java:205)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Run Code Online (Sandbox Code Playgroud)
所以你仍然能够识别发生的事情.你只需要注意原因.由于问题中的堆栈跟踪看起来不像典型Throwable.printStackTrace()输出,因此可能是产生此输出的代码忽略了异常的cause属性.
作为附录,我们可以检查如果使用自定义异常类型重新创建失败会发生什么:
import java.util.stream.IntStream;
public class Main
{
public static class CustomException extends RuntimeException {
public CustomException() {
System.err.println("will deliberately fail");
throw new NullPointerException();
}
private CustomException(String message) {
super(message);
}
}
public static void main(String[] args) {
Thread main=Thread.currentThread();
IntStream.range(0, 1000).parallel().forEach(i -> {
if(Thread.currentThread()!=main)
throw new CustomException("forced failure");
});
}
}
Run Code Online (Sandbox Code Playgroud)
将打印
will deliberately fail
Exception in thread "main" Main$CustomException: forced failure
at Main.lambda$main$0(Main.java:18)
at java.util.stream.ForEachOps$ForEachOp$OfInt.accept(ForEachOps.java:205)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Run Code Online (Sandbox Code Playgroud)
显示NullPointerException通过默认构造函数在反射重新创建期间抛出的内容保持未报告状态,而直接抛出来自另一个线程的原始异常.
| 归档时间: |
|
| 查看次数: |
3978 次 |
| 最近记录: |