Java 8 的 Stream API 是一个强大的工具,用于处理集合和数组的数据流操作。它提供了一种声明性、简洁且高效的方式来进行数据的过滤、转换、分组、统计等操作。本文将深入讲解 Stream API 的使用。
1. 什么是 Stream?
Stream 是一个数据管道,支持多种操作类型,包括:
- 中间操作:返回一个新的 Stream,如
filter()
、map()
等。 - 终端操作:触发计算并返回结果,如
forEach()
、collect()
等。
特点:
- 不存储数据,操作集合或数组的数据流。
- 支持链式调用。
- 延迟计算,只有在终端操作时才会执行。
- 可并行处理,提升性能。
2. 创建 Stream
常见创建方法:
- 从集合创建
- 从数组创建
- 从静态方法创建
- 自定义生成
示例代码:
import java.util.*;
import java.util.stream.*;
public class StreamCreation {
public static void main(String[] args) {
// 1. 从集合创建
List<String> list = Arrays.asList("Alice", "Bob", "Charlie");
Stream<String> streamFromList = list.stream();
// 2. 从数组创建
String[] array = {
"A", "B", "C"};
Stream<String> streamFromArray = Arrays.stream(array);
// 3. 使用 Stream.of()
Stream<Integer> streamFromValues = Stream.of(1, 2, 3, 4, 5);
// 4. 无限流生成
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2).limit(5);
infiniteStream.forEach(System.out::println); // 输出 0 2 4 6 8
}
}
3. Stream 的操作类型
3.1 中间操作
中间操作返回一个新的 Stream,用于链式调用。
常见中间操作:
filter()
- 按条件过滤元素。map()
- 将元素转换为另一种形式。sorted()
- 对流进行排序。distinct()
- 去重。limit()
和skip()
- 截取或跳过元素。
示例代码:
public class StreamIntermediate {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Bob");
names.stream()
.filter(name -> name.startsWith("B")) // 过滤以 B 开头的
.distinct() // 去重
.sorted() // 排序
.map(String::toUpperCase) // 转换为大写
.forEach(System.out::println); // 输出
// 输出:BOB
}
}
3.2 终端操作
终端操作触发流的计算并返回结果。
常见终端操作:
forEach()
- 遍历元素。collect()
- 将结果收集为集合或其他形式。count()
- 计算元素个数。reduce()
- 聚合操作。anyMatch()
/allMatch()
- 匹配检查。
示例代码:
import java.util.*;
import java.util.stream.Collectors;
public class StreamTerminal {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 1. collect
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出:[2, 4]
// 2. count
long count = numbers.stream().filter(n -> n > 3).count();
System.out.println(count); // 输出:2
// 3. reduce
int sum = numbers.stream().reduce(0, Integer::sum);
System.out.println(sum); // 输出:15
// 4. allMatch
boolean allPositive = numbers.stream().allMatch(n -> n > 0);
System.out.println(allPositive); // 输出:true
}
}
4. 高级用法:分组与分区
Collectors
提供了强大的工具来分组和分区数据。
示例代码:
import java.util.*;
import java.util.stream.*;
public class StreamGrouping {
public static void main(String[] args) {
List<String> items = Arrays.asList("apple", "banana", "orange", "apple", "orange", "banana", "apple");
// 分组
Map<String, Long> grouped = items.stream()
.collect(Collectors.groupingBy(item -> item, Collectors.counting()));
System.out.println(grouped); // 输出:{banana=2, orange=2, apple=3}
// 分区
Map<Boolean, List<String>> partitioned = items.stream()
.collect(Collectors.partitioningBy(item -> item.startsWith("a")));
System.out.println(partitioned); // 输出:{false=[banana, orange, orange, banana], true=[apple, apple, apple]}
}
}
5. 并行流
通过 parallelStream()
或 parallel()
,可以将流转换为并行流,以充分利用多核 CPU 的计算能力。
示例代码:
import java.util.*;
public class ParallelStreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 使用并行流计算
int sum = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.reduce(0, Integer::sum);
System.out.println(sum); // 输出:30
}
}
6. 注意事项与优化建议
- 避免修改流中的数据:流操作应该是无副作用的。
- 尽量减少使用并行流:并行流适合计算密集型任务,对于小数据集或 IO 密集型任务,可能会降低性能。
- 善用方法引用:提升代码可读性。