Java 8 流 - 计算器异常

标签 java java-8 java-stream reduce

运行以下代码示例以:
“线程“main”中的异常 java.lang.StackOverflowError”

import java.util.stream.IntStream;
import java.util.stream.Stream;

public class TestStream {

    public static void main(String[] args) {
        Stream<String> reducedStream = IntStream.range(0, 15000)
            .mapToObj(Abc::new)
            .reduce(
                Stream.of("Test")
                , (str , abc) -> abc.process(str)
                , (a , b) -> {throw new IllegalStateException();}
        );
        System.out.println(reducedStream.findFirst().get());
    }

    private static class Abc { 
        public Abc(int id) {
        }

        public Stream<String> process(Stream<String> batch) {
            return batch.map(this::doNothing);
        }

        private String doNothing(String test) {
            return test;
        }
    }
}

到底是什么导致了这个问题?此代码的哪一部分是递归的,为什么?

最佳答案

您的代码不是递归循环。您可以针对 IntStream 范围(即 1 或 100)使用较小的数字进行测试。在您的情况下,是导致问题的实际堆栈大小限制。正如一些评论中指出的那样,流是流程的方式。

对流的每次调用都会围绕原始流创建一个新的包装流。 'findFirst()' 方法向前一个流询问元素,后者又向前一个流询问元素。由于流不是真正的容器,而只是结果元素的指针。

包装器爆炸发生在 reduce 方法的累加器“(str , abc) -> abc.process(str)”中。该方法的实现在前一个操作的结果 (str) 上创建一个新的流包装器,馈入下一个迭代,在结果 (result(str))) 上创建一个新的包装器。因此,累积机制是包装器(递归)之一,而不是附加器(迭代)。因此,创建一个新的实际(扁平化)结果流而不是引用潜在结果将阻止爆炸,即

public Stream<String> process(Stream<String> batch) {
        return Stream.of(batch.map(this::doNothing).collect(Collectors.joining()));
    }

这个方法只是一个例子,因为你原来的例子没有任何意义,因为它什么都不做,这个例子也没有。它只是一个例子。它基本上将 map 方法返回的流的元素扁平化为单个字符串,并在这个具体字符串上创建一个新流,而不是在流本身上创建一个新流,这就是与原始代码的区别。

您可以使用定义每个线程堆栈大小的“-Xss”参数调整堆栈大小。默认值取决于平台,另请参阅此问题 'What is the maximum depth of the java call stack?'但增加时要小心,此设置适用于所有线程。

关于Java 8 流 - 计算器异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36656023/

相关文章:

java - 像在 SQL 中使用 Java lambda 一样对对象进行分组和求和?

java - 将视频嵌入到 Java 应用程序中?

java - 关闭两个 ExecutorService 实例

java - 点击按钮调用项目

java - 如何指定 lambda 表达式的类型?

Java 8 Optionals,组合语句

Java 8 类型推断错误

java - 如何使用 Java 8 Streams 将列表中的对象与 map 中的数据与条件进行匹配并保存到另一个 map

Java 流映射和收集 - 结果容器的顺序

java - 如何确定原始变量的原始类型?