Java 8 流何时被视为已使用?

2022-09-02 20:36:35

我的理解是,一旦执行了终端操作(例如 or ),Java 8 就被视为被使用。StreamforEach()count()

但是,下面的测试用例抛出一个 even,尽管是一个惰性的中间操作,只是作为两个语句调用。然而,我可以将两个过滤器操作链接到一个语句中,并且它可以工作。multipleFilters_separateIllegalStateExceptionfilter

@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);
}

由此,我假设 a 被视为在使用它的第一个语句之后被使用,无论该语句是否调用终端操作。这听起来对吗?Stream


答案 1

执行终端操作后,将被视为已使用 。但是,即使有多个中间操作也不应该为同一实例执行,如javadoc中所述:StreamStreamStream

流只能操作一次(调用中间或终端流操作)。例如,这排除了“分叉”流,其中同一源馈送两个或多个管道,或同一流的多个遍历。如果流实现检测到流正在被重用,它可能会引发 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);
}

答案 2

根据Stream Javadoc:

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

在您的例子中,对自身的调用检测到试图将流分叉到两个不同的流中。它不是等待并在添加终端操作后造成问题,而是执行先发制人的打击,以从任何堆栈跟踪中明确您获得的问题所在。filter


推荐