在Java中,流(Streams)是一个来自Java 8的重要特性,它提供了一种高效且表达力强的方式来处理数据集合(如List、Set等)。流API允许你以声明性方式处理数据集合(包括数组),支持复杂的查询/过滤、映射以及归约操作。与传统的集合操作相比,流操作可以更加简洁且易于理解,尤其是当处理复杂的数据转换和聚合时。
流的基本概念
在Java中,流是一组来自数据源的元素队列并支持聚合操作。数据源可以是集合、数组、I/O通道等。流操作分为中间操作和终端操作两种:
- 中间操作:返回流本身,因此可以链式调用多个中间操作。如
filter()
,map()
,sorted()
,limit()
等。 - 终端操作:产生一个结果或副作用,如:
forEach()
,collect()
,reduce()
,findAny()
,findFirst()
等。终端操作之后,流就不能再被使用了。
流的使用场景
流API非常适用于以下场景:
- 复杂的数据转换:当你需要对集合中的元素进行一系列复杂的转换时,流提供了一种清晰且简洁的方式来实现。
- 过滤和查找:快速筛选出满足特定条件的元素或查找单个元素。
- 聚合操作:如求和、最大值、最小值、平均值等,流提供了简洁的API来完成这些操作。
- 并行处理:流支持并行流,可以自动利用多核处理器,提高处理速度。
示例代码
下面是一个简单的Java流使用示例,假设我们有一个学生列表,我们想找出年龄大于18岁的学生,并计算他们的总分:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
class Student {
String name;
int age;
int score;
// 构造方法、getter和setter省略
}
public class StreamExample {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Alice", 20, 88),
new Student("Bob", 17, 92),
new Student("Charlie", 22, 78),
new Student("David", 18, 85)
);
// 找出年龄大于18岁的学生,并计算他们的总分
int totalScore = students.stream()
.filter(s -> s.age > 18)
.mapToInt(Student::getScore)
.sum();
System.out.println("Total score of students older than 18: " + totalScore);
// 使用collect收集结果到新的集合
List<String> names = students.stream()
.filter(s -> s.age > 18)
.map(Student::getName)
.collect(Collectors.toList());
System.out.println("Names of students older than 18: " + names);
}
}
注意事项
- 流操作不会修改源集合或数组。
- 流操作可以是顺序的,也可以是并行的。并行流可能会比顺序流更快,但这取决于你的具体任务和数据集的大小。
- 某些操作(如
findFirst()
或findAny()
)在并行流中的行为可能与顺序流不同。 - 流操作可能涉及多个步骤,但尽量保持流操作的简洁性,避免创建过于复杂的流管道。