forEach java 8 为大数据集抛出 StackOverflow 错误

forEach java 8 throws StackOverflow Error for big dataset

我正在尝试 -

        Stream<String> wat = Stream.empty();
        for (long i=0;i<10000000L;i++) {
            Stream<String> yaya = Stream.of("This iis a very biig string lsjdflkjkj lkasdjf lkjdsal");
            wat = Stream.of(wat, yaya).flatMap(Function.identity());
        }

        AtomicInteger i= new AtomicInteger();

        wat.forEach(st-> {
            i.incrementAndGet();
        });

        System.out.println(i);

以上抛出堆栈溢出错误-

java.lang.WhosebugError: null
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485) ~[?:1.8.0_275]
    at java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:272) ~[?:1.8.0_275]
    at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948) ~[?:1.8.0_275]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) ~[?:1.8.0_275]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) ~[?:1.8.0_275]
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) ~[?:1.8.0_275]

经过几次尝试和尝试,我能够通过使用流列表和使用嵌套 for 循环来解决这个问题 -

            List<Stream<String>> listOfStream = new ArrayList<>();
            for (long i=0;i<10000000L;i++) {
                Stream<String> yaya = Stream.of("This iis a very biig string lsjdflkjkj lkasdjf lkjdsal");                
                listOfStream.add(yaya);
            }

            AtomicInteger i= new AtomicInteger();
            listOfStream.forEach(st ->
                            st.forEach(sm -> {
                                i.incrementAndGet();
                            })
            );
            System.out.println(i);

此代码不会引发任何堆栈溢出问题。我试图查找各种文章,但无法理解为什么这是有效的而前者失败了。请帮忙。

您在初始 for 循环中所做的是构建一个非常大的对象树来描述您想要实现的目标。

将有一个 Stream 实现知道它想要对两个值执行 flatMap,其中之一将是一个 Stream 实现知道它想要对两个值执行 flatMap,其中一个将是一个 Stream 实现,它知道它想要对两个值执行 flatMap,其中一个将是 Stream ] 知道它想要对两个值执行 flatMap 的实现,其中之一将是一个 Stream 实现,它知道它想要对两个值执行 flatMap,其中之一这将是一个 Stream 实现,它知道它想要对两个值执行 flatMap,其中之一将是一个 Stream 实现,它知道它想要执行 [=12] =] 在两个值上,...,其中一个是空 Stream 实现。

在内部,它们被实现为相互包装并在必要时相互调用。

由于每个 Stream 实现都需要调用下一个并且该链有数千个对象深度,因此您至少需要这么深的堆栈才能完全执行它(实际上可能该数字的倍数,因为堆栈中可能还有一些 helper/intermediary 方法)。

在您的工作代码中,您只有一个 Stream 包含要迭代的 Stream 个对象的列表。所以调用深度非常有限:外层流一个接一个地委托给内层流。