java - Stream API - 如果 filter() 紧随其后,sorted() 操作如何工作?

标签 java sorting java-8 java-stream

采用以下代码,对列表进行排序,然后对其进行过滤:

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 知道所有以前遇到的元素,即它是有状态的。但是 mapfilter 不需要这些信息,它们是statelesslazy,这些操作总是处理元素从流源一次一个。

从技术上讲,通过单独查看单个元素来对管道的内容进行排序是不可能的。 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 之前的filtermap 操作将延迟应用于来自流源的每个元素,并且仅在需要时应用。 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/

相关文章:

java - 在 Android API 17 中打开/关闭移动数据

c++ - 按字符串C++对存储在 vector 中的对象进行排序

javascript - 对数字数组进行排序,使空值排在最后

java - 在 Jcard 上部署 javacard 小程序

java - setCellFactory 覆盖 updateItem 并换行文本

java - 将 LocalDate 和 LocalDateTime 序列化为 Unix 时间戳

c# - 使用 .Toarray 方法后在通用列表上排序

java - 如何使用 Java 8 streaming api 从 map 列表创建 map map

Java 8 - Consumer's andThen 的使用

java - 如何在 Java 8 中设置最小元空间