Java8流何时被认为是消费的?

Java8流何时被认为是消费的?,java,java-8,java-stream,Java,Java 8,Java Stream,我的理解是,一旦执行了诸如forEach()或count()之类的终端操作,就会认为Java 8流被消费 然而,下面的测试用例multipleFilters\u-separate抛出一个IllegalStateException,即使filter是一个惰性的中间操作,只是被称为两个语句。然而,我可以将这两个过滤操作链接到一个语句中,并且它可以工作 @Test(expected=IllegalStateException.class) public void multipleFilters_sep

我的理解是,一旦执行了诸如
forEach()
count()
之类的终端操作,就会认为Java 8
流被消费

然而,下面的测试用例
multipleFilters\u-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);
}
@Test(预期为IllegalStateException.class)
public void multipleFilters_separate(){
流积分=流积分(1.1,2.2,3.3);
内部过滤器(d->d>1.3);
ints.filter(d->d>2.3).forEach(System.out::println);
}
@试验
公共无效多重过滤器_管道(){
流积分=流积分(1.1,2.2,3.3);
内部过滤器(d->d>1.3)
.过滤器(d->d>2.3)
.forEach(System.out::println);
}

由此,我假设一个
被认为是在使用它的第一个语句之后被消费的,不管该语句是否调用终端操作。听起来对吗?

一旦执行了终端操作,就认为消耗了
流。但是,正如
javadoc中所述,对于同一
实例,甚至不应该执行多个中间操作:

一个流只能操作一次(调用中间或终端流操作)。例如,这排除了“分叉”流,即同一个源向两个或多个管道提供数据,或对同一个流进行多次遍历如果流实现检测到流正在被重用,它可能会抛出IllegalStateException。但是,由于某些流操作可能返回其接收器而不是新的流对象,因此可能无法在所有情况下检测重用

对于中间流操作,您应该调用上一个操作返回的
流上的下一个操作:

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);
}
public void multipleFilters_separate(){
流积分=流积分(1.1,2.2,3.3);
ints=ints.filter(d->d>1.3);
ints.filter(d->d>2.3).forEach(System.out::println);
}
根据以下内容:

流只能操作一次(调用中间或终端流操作)。例如,这排除了“分叉”流,即同一个源向两个或多个管道提供数据,或对同一个流进行多次遍历。如果流实现检测到流正在被重用,它可能会抛出
IllegalStateException
。然而,由于某些流操作可能返回其接收器而不是新的流对象,因此可能无法在所有情况下检测重用


在您的例子中,对
过滤器的调用本身检测到有人试图将您的流分成两个不同的流。添加终端操作后,它不是等待并导致问题,而是执行先发制人的攻击,以从任何堆栈跟踪中明确问题的确切位置。

ints.filter(d->d>1.3)
什么都不做。我不认为OP想表达的是这一点,因为很明显,这两个
filter
语句是多余的。不,我想评论一下你所说的“编写它的正确方法”。我感觉到分叉流是预期的用例,而不是您建议的链式流。@JoeC我不确定OP是否打算分叉流。我不是有意想到分叉流,只是为了可读性将我的操作拆分为单独的语句,并添加更详细的注释。但是,这样做似乎充满了危险。@craigcaulfield正如我所说,(如果你没有链接调用),你必须保留对每个
操作返回的
流的引用,并调用新
上的下一个操作。