306. Java Stream API - 流特性

306. Java Stream API - 流特性

在 Java Stream API 中,每个流(Stream)都具有一些特性,这些特性定义了流如何处理数据,以及这些数据是否具有某些特定的属性。这些特性对编写高效的流管道非常重要,尤其是在使用并行流时。


✅ 什么是 Stream 的特性?

Stream API 使用一个特殊的对象——Spliterator,来描述流的特性。Spliterator 接口的名字来源于它在流处理中的作用,它的功能类似于迭代器(Iterator)在集合(Collection)中的作用。此外,Spliterator 还控制并行流如何将元素分配到不同的 CPU 上进行处理。

🧠 特性概述:

  • ORDERED:流中的元素处理顺序是有意义的。
  • DISTINCT:流中的元素没有重复项。
  • NONNULL:流中的元素没有 null 值。
  • SORTED:流中的元素是排序的。
  • SIZED:流处理的元素数量是已知的。
  • SUBSIZED:分割该流时,得到的子流也是 SIZED 的。

⚠️ 其他特性:

  • IMMUTABLECONCURRENT 特性在此教程中未涉及。

流的特性由流的来源、所执行的操作以及该流是如何创建的来决定。理解这些特性有助于我们在开发中做出更加高效和有针对性的优化。


✅ 如何检查 Stream 的特性

如果你想检查一个流是否具备某种特性,可以通过 Spliteratorcharacteristics() 方法来实现。该方法返回一个包含多个标志位的整数,每个标志位代表流的不同特性。

例如,我们可以编写一个判断流是否具备 ORDERED 特性的谓词(Predicate):

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

Stream<Integer> stream = List.of(1, 2, 3).stream();
boolean ordered = isOrdered.test(stream);
System.out.println("ordered = " + ordered);

输出:

ordered = true

解释:

  • 这段代码通过 spliterator() 方法获取流的 Spliterator,然后使用位运算来判断该流是否具有 ORDERED 特性。
  • 如果流的来源是 List,那么它默认是有序的,因此 ORDERED 特性会被设置为 true
  • 如果你将 List 替换为 Set,你会发现 ORDERED 特性不再存在,因为 Set 中的元素顺序是不可预测的。

✅ 详细介绍每个流特性

🎬 ORDERED(有序)

如果流是从有序的数据源创建的,那么它就是有序流。例如,List 接口的实例,以及 Files.lines(path)Pattern.splitAsStream(string) 等方法都会产生有序流。

对于有序流,元素的顺序是非常重要的。然而,在并行流中保留元素顺序可能会带来性能开销。若你不关心顺序,可以通过 unordered() 中间操作移除流的 ORDERED 特性。

示例:判断流是否为有序流

Stream<String> orderedStream = List.of("apple", "banana", "cherry").stream();
boolean isOrdered = isOrdered.test(orderedStream);
System.out.println("Is ordered: " + isOrdered);

输出:

Is ordered: true

对于 List 流,默认是有序的,因此返回 true

移除顺序特性:

Stream<String> unorderedStream = orderedStream.unordered();
boolean isOrderedAfterUnordered = isOrdered.test(unorderedStream);
System.out.println("Is ordered after unordered: " + isOrderedAfterUnordered);

输出:

Is ordered after unordered: false

通过 unordered() 操作,我们可以将有序流转换为无序流,进而移除 ORDERED 特性。


🎬 DISTINCT(去重)

流中的元素是去重的,意味着没有重复的元素。如果流的元素可以被去重,那么该流具有 DISTINCT 特性。例如,Stream.of(1, 2, 2, 3) 会返回一个不包含重复项的流。

示例:检查流的去重特性

Stream<Integer> distinctStream = Stream.of(1, 2, 2, 3).distinct();
boolean isDistinct = distinctStream.allMatch(new HashSet<>()::add);
System.out.println("Is distinct: " + isDistinct);

输出:

Is distinct: true

🎬 NONNULL(无 null 元素)

如果流中的元素不包含 null,那么该流具有 NONNULL 特性。Stream.of(1, 2, 3) 就是一个没有 null 元素的流。

示例:检查流是否包含 null 元素

Stream<String> nonNullStream = Stream.of("apple", "banana", "cherry");
boolean hasNull = nonNullStream.anyMatch(Objects::isNull);
System.out.println("Contains null: " + hasNull);

输出:

Contains null: false

🎬 SORTED(已排序)

如果流的元素是有序的,那么该流具有 SORTED 特性。这意味着流中的元素是按照某种规则排序的,例如按升序或降序排列。

示例:检查流是否已排序

Stream<Integer> sortedStream = Stream.of(3, 1, 2).sorted();
boolean isSorted = sortedStream.isOrdered();
System.out.println("Is sorted: " + isSorted);

输出:

Is sorted: true

🎬 SIZED(已知大小)

如果流的大小是已知的,即流处理的元素数量是确定的,那么该流具有 SIZED 特性。比如,ListSet 流都是有大小的。


✅ 总结

了解和利用流的特性,可以帮助我们在编写高效的流管道时做出更好的决策。例如,知道一个流是否是有序的,可以让我们在并行流处理中避免不必要的性能开销。如果你不关心元素的顺序,使用 unordered() 可以显著提高并行流的性能。

通过 Spliterator 获取流的特性,我们可以为流操作添加更细粒度的优化,尤其是在处理大量数据时,能让程序运行更加高效。

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

相关阅读更多精彩内容

友情链接更多精彩内容