在Java 8中引入的Stream API无疑是对Java集合处理的一个重大革新,它提供了一种高效且表达力强的方式来处理数据集合(如List、Set)。Stream API 允许你以声明性方式处理数据集合,关注于“做什么”而非“怎么做”,从而提高了代码的可读性和可维护性。以下将深入探讨Java 8 Stream API的使用方法,通过实例展示其强大功能。
一、Stream API基础
Stream API的核心概念是流(Stream),它是对数据源(如集合)的一系列连续操作,这些操作包括过滤、映射、排序、归约等。流操作分为中间操作和终端操作:
- 中间操作:返回流本身,可以链式调用多个中间操作。
- 终端操作:产生结果或副作用,如forEach、collect、reduce等,之后流就不能再被使用了。
创建流
可以从集合、数组等数据源中创建流:
List<String> list = Arrays.asList("apple", "banana", "cherry");
Stream<String> stream = list.stream(); // 从集合创建流
String[] array = {"dog", "cat", "bird"};
Stream<String> arrayStream = Arrays.stream(array); // 从数组创建流
流的常用操作
1. 过滤(Filter)
过滤操作通过filter
方法实现,它接受一个谓词(Predicate),返回所有符合该谓词的元素组成的流。
List<String> filtered = list.stream()
.filter(s -> s.startsWith("a")) // 过滤以'a'开头的字符串
.collect(Collectors.toList()); // 收集结果
2. 映射(Map)
映射操作通过map
方法实现,它接受一个函数(Function),将流中的每个元素转换成另一种形式。
List<Integer> lengths = list.stream()
.map(String::length) // 获取每个字符串的长度
.collect(Collectors.toList());
3. 排序(Sorted)
对流中的元素进行排序,分为自然排序和自定义排序。
List<String> sorted = list.stream()
.sorted() // 自然排序
.collect(Collectors.toList());
// 自定义排序
List<Person> people = Arrays.asList(/* 假设这里有一些Person对象 */);
List<Person> sortedByAge = people.stream()
.sorted(Comparator.comparingInt(Person::getAge))
.collect(Collectors.toList());
4. 归约(Reduce)
归约操作通过reduce
方法实现,它可以将流中的所有元素反复结合起来,得到一个值。
Optional<String> concatenated = list.stream()
.reduce((s1, s2) -> s1 + "," + s2); // 将字符串用逗号连接
// 也可以使用reduce的另一种形式计算总和
int sum = list.stream()
.mapToInt(String::length) // 将字符串映射为长度
.sum(); // 直接求和
5. 收集(Collect)
收集操作通过collect
方法实现,它可以将流中的元素收集到一个容器(如List、Set、Map)中,或者进行更复杂的归约操作。
List<String> collected = list.stream()
.filter(s -> s.startsWith("a"))
.collect(Collectors.toList()); // 收集到List中
// 收集到Map中
Map<Boolean, List<String>> partitioned = list.stream()
.collect(Collectors.partitioningBy(s -> s.startsWith("a")));
二、Stream API的高级用法
除了上述基本操作外,Stream API还提供了一些高级用法,如并行流、复杂收集操作等。
并行流
并行流允许你利用多核处理器,对集合进行并行处理,从而提高性能。通过调用parallelStream()
方法获取并行流。
List<Integer> numbers = Arrays.asList(/* 一些整数 */);
long sum = numbers.parallelStream()
.mapToInt(Integer::intValue)
.sum(); // 并行求和
注意,并非所有情况下并行流都比顺序流快,它取决于你的数据源大小、处理操作的复杂度以及你的硬件环境。
复杂收集操作
Collectors类提供了多种收集器(Collector),用于实现复杂的收集操作,如分组、分区、连接字符串等。
// 分组
Map<Integer, List<String>> groupedByLength = list.stream()
.collect(Collectors.groupingBy(String::length));
// 分区(基于谓词)
Map<Boolean, List<String>> partitioned = list.stream()
.collect(Collectors.partitioningBy(s -> s.startsWith("a")));
// 连接字符串
String joined = list.stream()
.collect(Collectors.joining(", "));
三、实际应用场景
Stream API在数据处理、文件IO、数据库操作等多个领域都有广泛的应用。以下是一个简单的应用场景示例:
示例:处理学生成绩数据
假设你有一个学生成绩的数据集(List<StudentScore>
),你需要筛选出所有成绩及格的学生,并按成绩从高到低排序,最后收集到一个列表中。
List<StudentScore> scores = /* 假设这里有一些StudentScore对象 */;
List<StudentScore> passingScores = scores.stream()
.filter(score -> score.getScore() >= 60) // 筛选出成绩及格的学生
.sorted(Comparator.comparingInt(StudentScore::getScore).reversed()) // 按成绩降序排序
.collect(Collectors.toList()); // 收集到List中
// 打印结果
passingScores.forEach(score -> System.out.println(score));
四、总结
Java 8的Stream API为集合处理提供了一种全新的、声明式的编程模型,极大地提高了代码的可读性和可维护性。通过掌握Stream API的基本操作和高级用法,你可以更高效地处理数据集合,编写出更加简洁、优雅的代码。在实际开发中,不妨多尝试使用Stream API来替代传统的集合遍历和条件判断,相信你会爱上这种编程方式。
在探索Stream API的过程中,不妨关注“码小课”网站,这里不仅有丰富的Java教程和实例,还有来自社区的宝贵经验和最佳实践分享,帮助你更深入地理解和掌握Java 8及其新特性。