运行以下代码示例以:
“线程中的异常”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;
}
}
}
究竟是什么导致了这个问题?这段代码的哪一部分是递归的,为什么?
答案 0 :(得分:2)
您的代码不是递归循环的。您可以使用较小的数字测试IntStream范围(即1或100)。在您的情况下,它是导致问题的实际堆栈大小限制。正如一些评论中指出的那样,它是流的流程。
流上的每次调用都会在原始循环周围创建一个新的包装器流。 &#39; findFirst()&#39;方法向前一个流请求元素,而元素又要求前一个元素流。由于流不是真正的容器,而只是指向结果元素的指针。
包装器爆炸发生在reduce方法&#39;累加器&#39;(str,abc) - &gt; abc.process(STR)&#39 ;.该方法的实现在前一个操作的结果(str)上创建一个新的流包装器,进入下一个迭代,在结果上创建一个新的包装器(result(str)))。因此,累积机制是包装器(递归)之一而不是appender(迭代)之一。因此,创建一个实际(扁平化)结果的新流而不是参考潜在结果将阻止爆炸,即
public Stream<String> process(Stream<String> batch) {
return Stream.of(batch.map(this::doNothing).collect(Collectors.joining()));
}
这个方法只是一个例子,因为你的原始例子没有任何意义,因为它什么都不做,这个例子也没有。它只是一个例子。它基本上将map方法返回的流的元素展平为单个字符串,并在此具体字符串上创建新流,而不是在流本身上创建新流,这与原始代码的区别。
您可以使用&#39; -Xss&#39;来调整stacksize。参数,定义每个线程的堆栈大小。默认值取决于平台,另请参阅此问题'What is the maximum depth of the java call stack?'但是在增加时要小心,此设置适用于所有线程。