前言
在当今的 Java 编程世界中,Stream 流的出现为数据处理带来了极大的便利和效率提升。它提供了一种简洁、直观且功能强大的方式来操作和处理集合数据。接下来,让我们深入探索 Java Stream 的奥秘。
一、Stream 流是什么?
Stream 流是 Java 8 中引入的一种处理集合数据的编程模型。它不是数据结构,而是一种对数据进行操作和计算的方式。Stream 流将数据处理的逻辑表达从传统的命令式编程转变为声明式编程,使开发者能够更专注于描述需要对数据执行的操作,而无需关心具体的实现细节和迭代过程。
通过 Stream 流,我们可以以一种更加简洁和直观的方式对集合中的元素进行过滤、映射、排序、聚合等操作,从而大大提高了代码的可读性和可维护性。
二、流的分类
顺序流
顺序流是按照元素在集合中的自然顺序依次处理的流。它在单个线程中按顺序执行操作,适用于数据量较小或者对处理顺序有严格要求的情况。
例如,如果我们有一个整数列表 [1, 2, 3, 4, 5]
,使用顺序流进行简单的求和操作,会依次对每个元素进行处理。
并行流
并行流则利用多核处理器的优势,同时在多个线程中处理数据。这对于处理大规模数据集或计算密集型任务能够显著提高性能。
例如,对于一个包含大量元素的列表,并行流可以同时在多个线程中进行过滤操作,从而加快处理速度。
区别
顺序流和并行流的主要区别在于处理数据的方式和性能表现。顺序流遵循元素的原始顺序,适合顺序敏感的操作和小型数据集。并行流通过并发处理提高速度,但可能会改变元素的处理顺序,并且在某些情况下可能需要额外的同步和协调来保证结果的正确性。
在实际应用中,选择使用顺序流还是并行流需要根据具体的场景和需求来决定。
三、获取流的常用方式
1. 通过集合获取流
大多数集合类,如 List
、Set
等,都提供了 stream()
方法来获取对应的流。
List<String> names = List.of("Alice", "Bob", "Charlie");Stream<String> nameStream = names.stream();
2. 通过数组获取流
可以使用 Arrays.stream()
方法将数组转换为流。
int[] numbers = {1, 2, 3, 4, 5};Stream<int[]> numberStream = Arrays.stream(numbers);
3. 通过 Stream.of()
方法获取流
Stream.of()
方法允许直接传入一系列元素来创建流。
Stream<String> fruitStream = Stream.of("Apple", "Banana", "Orange");
四、常用方法用法
4.1 遍历 / 匹配(foreach
、find
、match
)
forEach
方法用于遍历流中的每个元素并执行指定的操作。
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");names.forEach(name -> System.out.println(name));
find
方法用于查找流中满足条件的第一个元素。
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");Optional<String> foundName = names.find(name -> name.startsWith("A"));
match
方法用于判断流中的元素是否满足指定的条件。
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");boolean allStartWithA = names.allMatch(name -> name.startsWith("A"));
4.2 筛选(filter
)
filter
方法用于根据给定的条件过滤流中的元素,只保留满足条件的元素。
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Stream<Integer> filteredNumbers = numbers.filter(num -> num > 2);
4.3 聚合(max
、min
、count
)
max
方法用于获取流中的最大值。
Stream<Integer> numbers = Stream.of(1, 5, 3, 7, 2);Optional<Integer> maxNumber = numbers.max(Integer::compareTo);
min
方法用于获取流中的最小值。
Stream<Integer> numbers = Stream.of(1, 5, 3, 7, 2);Optional<Integer> minNumber = numbers.min(Integer::compareTo);
count
方法用于计算流中元素的数量。
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");long count = names.count();
4.4 映射(map
、flatMap
)
map
方法用于将流中的每个元素按照指定的函数进行映射转换。
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");Stream<Integer> nameLengths = names.map(name -> name.length());
flatMap
方法用于将流中的每个元素转换为一个流,并将这些流扁平化合并为一个新的流。
Stream<List<String>> lists = Stream.of(List.of("A", "B"), List.of("C", "D"));Stream<String> flattened = lists.flatMap(list -> list.stream());
4.5 归约(reduce
)
reduce
方法用于对流中的元素进行归约操作,将多个元素合并为一个结果。
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Optional<Integer> sum = numbers.reduce((a, b) -> a + b);
4.6 收集(collect
)
collect
方法用于将流中的元素收集到一个新的集合或其他数据结构中。
4.6.1 归集(toList
、toSet
、toMap
)
tName, Person::getAge));
4.6.2 统计(count
、averaging
)
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Double average = numbers.collect(Collectors.averagingInt(num -> num));
4.6.3 分组(partitioningBy
、groupingBy
)
Stream<Person> people = Stream.of(new Person("Alice", 20), new Person("Bob", 30), new Person("Charlie", 20));Map<Boolean, List<Person>> partitioned = people.collect(Collectors.partitioningBy(person -> person.getAge() > 25));Stream<Person> people = Stream.of(new Person("Alice", 20), new Person("Bob", 30), new Person("Charlie", 20));Map<Integer, List<Person>> grouped = people.collect(Collectors.groupingBy(Person::getAge));
4.6.4 接合(joining
)
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");String joinedNames = names.collect(Collectors.joining(", "));
4.7 排序(sorted
)
Stream<String> names = Stream.of("Charlie", "Alice", "Bob");Stream<String> sortedNames = names.sorted();
4.8 去重、合并(distinct
、skip
、limit
)
distinct
方法用于去除流中的重复元素。
Stream<Integer> numbers = Stream.of(1, 2, 2, 3, 3, 3);Stream<Integer> distinctNumbers = numbers.distinct();
skip
方法用于跳过流中的前 n
个元素。
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Stream<Integer> skippedNumbers = numbers.skip(2);
limit
方法用于获取流中的前 n
个元素。
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Stream<Integer> limitedNumbers = numbers.limit(3);
五、总结
Java 的 Stream 流为我们提供了丰富而强大的功能,使得数据处理变得更加简洁、高效和灵活。通过合理地运用获取流的方式和各种常用方法,我们能够以更加优雅和直观的方式解决复杂的数据处理问题。在实际开发中,根据具体的业务需求和数据特点,精心选择和组合使用 Stream 流的方法,将大大提升代码的质量和开发效率。希望通过本文的介绍,您对 Java Stream 有了更深入的理解和掌握,能够在今后的编程实践中充分发挥其优势,编写出更加出色的代码。