我的理解是,一旦执行终端操作(例如Stream
或forEach()
),就会认为Java 8 count()
被使用。
但是,下面的测试用例multipleFilters_separate
会抛出IllegalStateException
,即使filter
是一个懒惰的中间操作,只是被称为两个语句。然而,我可以将两个过滤操作链接到一个语句中并且它可以工作。
@Test(expected=IllegalStateException.class)
public void multipleFilters_separate() {
Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
ints.filter(d -> d > 1.3);
ints.filter(d -> d > 2.3).forEach(System.out::println);
}
@Test
public void multipleFilters_piped() {
Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
ints.filter(d -> d > 1.3)
.filter(d -> d > 2.3)
.forEach(System.out::println);
}
由此,假设Stream
被认为是在使用它的第一个语句之后被消耗,无论该语句是否调用终端操作。听起来不错吗?
答案 0 :(得分:20)
执行终端操作后,将认为Stream
已消耗。但是,即使多个中间操作也不应该针对同一个Stream
实例执行,如Stream
javadoc中所述:
流应该操作(仅调用中间或终端流操作)。例如,这排除了&#34;分叉&#34;流,相同的源提供两个或多个管道,或同一流的多个遍历。 如果流实现检测到正在重用流,则可能会抛出IllegalStateException。但是,由于某些流操作可能会返回其接收者而不是新的流对象,因此可能无法检测到所有流对象的重用案例。
如果是中间流操作,您应该调用上一个操作返回的Stream
上的下一个操作:
public void multipleFilters_separate() {
Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
ints = ints.filter(d -> d > 1.3);
ints.filter(d -> d > 2.3).forEach(System.out::println);
}
答案 1 :(得分:11)
应该只对一个流进行操作(调用中间或终端流操作)。例如,这排除了“分叉”流,其中相同的源提供两个或更多个管道,或者同一个流的多个遍历。如果流实现检测到流正在被重用,则它可能会抛出
IllegalStateException
。但是,由于某些流操作可能会返回其接收器而不是新的流对象,因此可能无法在所有情况下检测重用。
在您的情况下,对filter
本身的调用是检测到将您的流分成两个不同的流的尝试。它不是在添加终端操作后等待并导致问题,而是执行先发制人的攻击,以便从任何堆栈跟踪中清楚地了解您的问题所在。