310. Java Stream API -大小特性和子大小特性流

310. Java Stream API -大小特性和子大小特性流(Sized and Subsized Streams)

在 Java 中,流的大小特性(SIZED)子大小特性(SUBSIZED)在处理数据时非常重要,尤其是在使用并行流时。掌握这两个特性有助于优化并行流的性能。

SIZED 流

SIZED 流指的是已知流中元素的数量的流。简单来说,创建流时,如果能够提前知道流中元素的数量,那么这个流就是 SIZED 流。

示例:

  • 集合(Collection):所有实现了 Collection 接口的集合类(如 ArrayListHashSet)都可以创建一个 SIZED 流,因为集合有一个 size() 方法,直接可以获取元素的数量。
  • 无法获取大小的流:某些流(如通过 Files.lines(path)Pattern.splitAsStream(line) 创建的流)不能在流创建时知道元素的数量,必须通过实际处理流的数据才能获得大小,因此它们不是 SIZED 流。

示例代码:检查一个 ArrayList 是否是 SIZED 流

Predicate<Stream<?>> isSized =
        stream -> ((stream.spliterator().characteristics() & Spliterator.SIZED) != 0);

List<String> strings = new ArrayList<>();
System.out.println("ArrayList is sized? " + isSized.test(strings.stream()));

输出:

ArrayList is sized? true

这段代码演示了如何检查 ArrayList 创建的流是否具有 SIZED 特性。由于 ArrayList 可以在创建流时知道其大小,因此它是一个 SIZED 流。

SUBSIZED 流

SUBSIZED 流涉及到流在并行处理时的分割方式。在并行流中,流会被分成多个部分并分配给不同的 CPU 核心进行计算。能够分割成相等大小子部分的流称为 SUBSIZED 流。

为什么有些流是 SUBSIZED 而有些不是?

  • ArrayListArrayList 内部存储元素的数组非常适合分割,可以直接将其拆分成两个大小相等的部分,因此它是 SIZEDSUBSIZED 的流。
  • HashSet:虽然 HashSet 是 SIZED 流,但它的存储方式不同。由于 HashSet 是通过哈希算法存储元素的,无法直接知道如何将其拆分成大小相等的部分。因此,HashSet 的流是 SIZED,但不是 SUBSIZED 流。

示例代码:检查 HashSet 是否是 SUBSIZED 流

Predicate<Stream<?>> isSubSized =
        stream -> ((stream.spliterator().characteristics() & Spliterator.SUBSIZED) != 0);

Set<String> strings = new HashSet<>();
System.out.println("HashSet is sized? " + isSized.test(strings.stream()));
System.out.println("HashSet is subsized? " + isSubSized.test(strings.stream()));

输出:

HashSet is sized? true
HashSet is subsized? false

这段代码演示了如何检查一个 HashSet 创建的流是否是 SUBSIZED 流。虽然 HashSet 是 SIZED 流,但由于它的存储方式,无法分割成大小相等的子部分,因此它不是 SUBSIZED 流。

流转换对 SIZED 和 SUBSIZED 特性的影响

  • 保持 SIZED 和 SUBSIZED 特性:像 map()sorted() 等操作不会改变流的 SIZED 和 SUBSIZED 特性。
  • 丧失 SIZED 和 SUBSIZED 特性:像 filter()distinct()flatMap() 这样的操作会丧失流的 SIZED 和 SUBSIZED 特性。

示例:映射流时保持特性

Stream<String> nonSubSizedStream = Stream.of("apple", "banana", "cherry");
Stream<String> mappedStream = nonSubSizedStream.map(String::toUpperCase);
System.out.println("Mapped stream is sized? " + isSized.test(mappedStream));  // true

nonSubSizedStream = Stream.of("apple", "banana", "cherry");
mappedStream = nonSubSizedStream.map(String::toUpperCase);
System.out.println("Mapped stream is subsized? " + isSubSized.test(mappedStream));  // true

输出:

Mapped stream is sized? true
Mapped stream is subsized? true

这段代码演示了对流进行 map() 操作后,流仍然保留了 SIZED 和 SUBSIZED 特性。

示例:过滤流时丧失特性

Stream<String> filteredStream = nonSubSizedStream.filter(s -> s.length() > 5);
System.out.println("Filtered stream is sized? " + isSized.test(filteredStream));  // false
System.out.println("Filtered stream is subsized? " + isSubSized.test(filteredStream));  // false

输出:

iltered stream is sized? false
Filtered stream is subsized? false

这段代码演示了对流进行 filter() 操作后,丧失了 SIZED ,SUBSIZED 特性。

并行流的优化

对于并行流,SIZED 和 SUBSIZED 特性尤其重要。通过确保流是 SIZED 且 SUBSIZED,可以使流在并行计算时更加高效。例如,当流的子部分大小已知时,流的并行执行能够更均匀地分配计算任务,从而减少处理时间。

小结:

  1. SIZED 流:知道流中元素的数量,适用于那些可以快速获取大小信息的数据源,如 ArrayListHashSet
  2. SUBSIZED 流:能够将流分割成大小相等的部分,适用于那些数据结构具有明确划分和大小的流,如 ArrayList
  3. 流转换:某些流操作(如 map()sorted())会保留 SIZED 和 SUBSIZED 特性,而其他操作(如 filter()flatMap()distinct())可能会丧失这些特性。
  4. 并行流优化:确保流是 SIZED 和 SUBSIZED 对于并行流的性能至关重要。

掌握这两个特性及其如何影响流的处理方式,可以帮助你在 Java 流处理中更好地优化性能,尤其是在并行处理时。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容