为什么这个java流作了两次?

2022-09-01 19:00:30

Java 8 API 说:

在执行管道的终端操作之前,不会开始遍历管道源。

那么为什么下面的代码会抛出:

java.lang.IllegalStateException:流已作或关闭

Stream<Integer> stream = Stream.of(1,2,3);
stream.filter( x-> x>1 );
stream.filter( x-> x>2 ).forEach(System.out::print);

根据 API 执行的第一个筛选操作不应在流上运行。


答案 1

发生这种情况是因为您忽略了 的返回值。filter

Stream<Integer> stream = Stream.of(1,2,3);
stream.filter( x-> x>1 ); // <-- ignoring the return value here
stream.filter( x-> x>2 ).forEach(System.out::print);

Stream.filter 返回一个新的元素,该元素由此流中与给定谓词匹配的元素组成。但重要的是要注意,这是一个新的流。旧的过滤器在添加时已经操作过。但新的不是。Stream

引用自 Stream Javadoc:

流只能操作一次(调用中间或终端流操作)。

在本例中,是在旧 Stream 实例上运行的中间操作。filter

所以这段代码可以正常工作:

Stream<Integer> stream = Stream.of(1,2,3);
stream = stream.filter( x-> x>1 ); // <-- NOT ignoring the return value here
stream.filter( x-> x>2 ).forEach(System.out::print);

正如Brian Goetz所指出的,你通常会把这些调用链接在一起:

Stream.of(1,2,3).filter( x-> x>1 )
                .filter( x-> x>2 )
                .forEach(System.out::print);

答案 2

filter()方法使用流并返回您在示例中忽略的另一个实例。Stream

filter是中间操作,但不能在同一流实例上调用 filter 两次

您的代码应按如下方式编写:

Stream<Integer> stream = Stream.of(1,2,3);
                               .filter( x-> x>1 )
                               .filter( x-> x>2);
stream.forEach(System.out::print);

由于筛选器是中间操作,因此在调用这些方法时不会执行“任何操作”。调用方法时,所有作业都得到实际处理forEach()


推荐