Collection.stream()
是 Java 8 引入的核心 API,它提供了一种声明式(Declarative)的方式来处理集合数据,结合 Lambda 表达式和函数式接口,可以极大简化集合操作。
1. stream()
基础用法
(1) 创建 Stream
ini
List<String> list = Arrays.asList("a", "b", "c", "d");
// 1. 顺序流(单线程)
Stream<String> stream = list.stream();
// 2. 并行流(多线程)
Stream<String> parallelStream = list.parallelStream();
(2) 常用操作
操作类型 | 方法 | 说明 |
---|---|---|
中间操作 | filter() |
过滤元素 |
map() |
转换元素 | |
sorted() |
排序 | |
distinct() |
去重 | |
limit() / skip() |
截取 / 跳过 | |
终止操作 | forEach() |
遍历 |
collect() |
收集结果 | |
reduce() |
归约 | |
count() |
计数 | |
anyMatch() / allMatch() / noneMatch() |
条件匹配 |
2. 实战案例
(1) 过滤(filter
)
ini
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 过滤长度 > 3 的名字
List<String> filteredNames = names.stream()
.filter(name -> name.length() > 3)
.collect(Collectors.toList());
System.out.println(filteredNames); // [Alice, Charlie, David]
(2) 映射(map
)
ini
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
// 每个数字平方
List<Integer> squares = numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println(squares); // [1, 4, 9, 16]
(3) 排序(sorted
)
ini
List<String> names = Arrays.asList("Bob", "Alice", "David", "Charlie");
// 按字母顺序排序
List<String> sortedNames = names.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sortedNames); // [Alice, Bob, Charlie, David]
(4) 去重(distinct
)
ini
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3);
// 去重
List<Integer> distinctNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
System.out.println(distinctNumbers); // [1, 2, 3]
(5) 统计(count
, sum
, average
)
scss
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 计算总和
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum();
// 计算平均值
double avg = numbers.stream()
.mapToInt(Integer::intValue)
.average()
.orElse(0.0);
System.out.println("Sum: " + sum); // Sum: 15
System.out.println("Avg: " + avg); // Avg: 3.0
(6) 分组(groupingBy
)
ini
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 按首字母分组
Map<Character, List<String>> groupedNames = names.stream()
.collect(Collectors.groupingBy(name -> name.charAt(0)));
System.out.println(groupedNames);
// {A=[Alice], B=[Bob], C=[Charlie], D=[David]}
(7) 归约(reduce
)
ini
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 计算乘积
int product = numbers.stream()
.reduce(1, (a, b) -> a * b);
System.out.println(product); // 120
3. 高级用法
(1) flatMap
(扁平化流)
scss
List<List<Integer>> nestedList = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6)
);
// 扁平化为单层 List
List<Integer> flatList = nestedList.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(flatList); // [1, 2, 3, 4, 5, 6]
(2) peek
(调试流)
rust
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 打印中间结果
List<String> result = names.stream()
.peek(System.out::println) // 调试
.filter(name -> name.length() > 3)
.collect(Collectors.toList());
// 输出:
// Alice
// Bob
// Charlie
System.out.println(result); // [Alice, Charlie]
**(3) findFirst
/ findAny
**
ini
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 查找第一个匹配的元素
Optional<String> firstMatch = names.stream()
.filter(name -> name.startsWith("A"))
.findFirst();
System.out.println(firstMatch.orElse("Not found")); // Alice
(4) Collectors.joining
(字符串拼接)
ini
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 拼接字符串
String joined = names.stream()
.collect(Collectors.joining(", "));
System.out.println(joined); // Alice, Bob, Charlie
4. 并行流(parallelStream
)
(1) 基本使用
ini
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 并行计算平方和
int sum = numbers.parallelStream()
.mapToInt(n -> n * n)
.sum();
System.out.println(sum); // 385
(2) 适用场景
- 大数据量(> 10,000 条数据)
- CPU 密集型计算(如数学运算)
- 无状态操作 (如
map
、filter
)
(3) 注意事项
- 线程安全问题(避免修改共享数据)
- 顺序问题 (
forEach
不保证顺序) - 性能测试(小数据量可能更慢)
5. 性能优化
(1) 避免多次 stream()
❌ 错误写法(多次创建流):
ini
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 错误:多次 stream()
long count = numbers.stream().filter(n -> n > 2).count();
int sum = numbers.stream().mapToInt(n -> n).sum();
✅ 正确写法(复用流):
ini
IntStream intStream = numbers.stream().mapToInt(n -> n);
long count = intStream.filter(n -> n > 2).count();
int sum = intStream.sum(); // 错误!流只能消费一次
解决方案 (使用 Supplier
):
ini
Supplier<Stream<Integer>> streamSupplier = () -> numbers.stream();
long count = streamSupplier.get().filter(n -> n > 2).count();
int sum = streamSupplier.get().mapToInt(n -> n).sum();
(2) 使用 primitive streams
(IntStream
, LongStream
, DoubleStream
)
ini
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 避免自动拆箱
int sum = numbers.stream()
.mapToInt(Integer::intValue) // IntStream
.sum();
6. 总结
场景 | 推荐操作 |
---|---|
过滤数据 | filter() |
转换数据 | map() / flatMap() |
排序 | sorted() |
去重 | distinct() |
统计 | count() / sum() / average() |
分组 | Collectors.groupingBy() |
归约 | reduce() |
并行计算 | parallelStream() |
最佳实践:
- 优先使用
stream()
替代传统for
循环。 - 避免多次创建流,尽量复用。
- 大数据量考虑
parallelStream
,但需测试性能。 - **使用
primitive streams
** 提升性能。