采用以下代码,对列表进行排序,然后对其进行过滤:
public static void main(String[] args) {
List<Integer> list = List.of(3,2,1);
List<Integer> filtered = list.stream()
.sorted() // Does sorted() sort the entire array first ? Then pass the entire sorted output to filter ?
.filter(x -> x < 3)
.collect(Collectors.toList());
System.out.println(filtered);
}
整个 sort()
是否先发生,然后传递给 filter()
?
那么这不是违反了流应该做的事情吗?
我的意思是,它们应该一次处理一个元素。
最佳答案
Does the entire sort() happen first then gets passed to filter() ?
Then isn't that a violation of what streams are suppose to do ?
不,不是。看看 documentation of the Stream IPA :
Intermediate operations are further divided into stateless and stateful operations. Stateless operations, such as filter and map, retain no state from previously seen element when processing a new element -- each element can be processed independently of operations on other elements. Stateful operations, such as distinct and sorted, may incorporate state from previously seen elements when processing new elements.
Stateful operations may need to process the entire input before producing a result. For example, one cannot produce any results from sorting a stream until one has seen all elements of the stream. As a result, under parallel computation, some pipelines containing stateful intermediate operations may require multiple passes on the data or may need to buffer significant data. Pipelines containing exclusively stateless intermediate operations can be processed in a single pass, whether sequential or parallel, with minimal data buffering.
这意味着 sorted
知道所有以前遇到的元素,即它是有状态的。但是 map
和 filter
不需要这些信息,它们是stateless 和 lazy,这些操作总是处理元素从流源一次一个。
从技术上讲,通过单独查看单个元素来对管道的内容进行排序是不可能的。 sorted
“一次”对所有 元素进行操作,并将排序后的流传递给下一个操作。您可能会认为 sorted
好像它成为流的新来源。
我们来看看下面的流,分析一下它是如何处理的:
Stream.of("foo", "bar", "Alice", "Bob", "Carol")
.filter(str -> !str.contains("r")) // lazy processing
.peek(System.out::println)
.map(String::toUpperCase) // lazy processing
.peek(System.out::println)
.sorted() // <--- all data is being dumped into memory
.peek(System.out::println)
.filter(str -> str.length() > 3) // lazy processing
.peek(System.out::println)
.findFirst(); // <--- the terminal operation
sorted
之前的filter
和map
操作将延迟应用于来自流源的每个元素,并且仅在需要时应用。 IE。 filter 将应用于 "foo"
,它成功通过 filter 并通过 map 操作进行转换.然后 filter 被应用于 “bar”
,它不会到达 map。然后轮到 “Alice”
传递 filter,然后 map 将在该字符串上执行。等等。
请记住,sorted()
需要所有数据来完成它的工作,因此 第一个过滤器 将对来自源和 map 将应用于通过过滤器的每个元素。
然后 sorted()
操作会将流中的所有内容转储到内存中,并对通过第一个过滤器的元素进行排序。
并且在排序之后,所有元素将再次被延迟地一次处理一个。因此,第二个过滤器将仅应用一次(尽管3
元素已通过第一个过滤器并已排序)。 “Alice”
将通过第二个过滤器 并到达将返回此字符串的终端操作 findFirst()
。
查看 peek()
的调试输出 make,执行过程如上所述。
关于java - Stream API - 如果 filter() 紧随其后,sorted() 操作如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72118729/