Java 8 引入了 Stream
流式编程,大大简化了集合的遍历、筛选、映射、聚合等操作。它借鉴了函数式编程的思想,使得数据处理更加简洁、高效、可读。本文将深入介绍 Java 中常用的流处理方法,并通过丰富的代码示例加以说明,帮助大家掌握流式编程的核心技巧。
一、什么是 Stream?
Stream 是 Java 8 引入的一个新特性,用于支持对集合数据进行函数式操作。它不是集合本身,而是一种“数据渠道”,可以用来对集合中的数据进行一系列复杂操作,如筛选、映射、排序、统计等。
流处理具有以下特点:
- 不存储数据;
- 不会修改源数据;
-
延迟执行,只有触发终止操作(如
collect
、forEach
)时才会执行。
二、Stream 的基本使用流程
collection.stream() // 获取流
.filter(...) // 中间操作
.map(...)
.sorted(...)
.collect(...) // 终止操作
Stream 的操作分为两大类:
-
中间操作(Intermediate):返回新的 Stream,可继续链式调用(如
filter
,map
,sorted
); -
终止操作(Terminal):触发实际执行(如
collect
,forEach
,count
)。
三、常用中间操作详解
1. filter(Predicate)
对元素进行筛选,只保留符合条件的元素。
List<String> names = List.of("Alice", "Bob", "Charlie");
List<String> result = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
输出:[Alice]
2. map(Function)
对每个元素进行转换处理。
List<String> words = List.of("apple", "banana", "cherry");
List<Integer> lengths = words.stream()
.map(String::length)
.collect(Collectors.toList());
输出:[5, 6, 6]
3. flatMap(Function)
将多个流“扁平化”为一个流。
List<List<String>> nested = List.of(
List.of("A", "B"),
List.of("C", "D")
);
List<String> flat = nested.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
输出:[A, B, C, D]
4. distinct()
去除重复元素。
List<Integer> nums = List.of(1, 2, 2, 3, 3, 3);
List<Integer> unique = nums.stream().distinct().collect(Collectors.toList());
输出:[1, 2, 3]
5. sorted()
默认按照自然顺序排序,也可自定义排序规则。
List<String> names = List.of("Tom", "Jerry", "Alice");
List<String> sorted = names.stream()
.sorted()
.collect(Collectors.toList());
输出:[Alice, Jerry, Tom]
按长度排序:
List<String> sortedByLength = names.stream()
.sorted(Comparator.comparingInt(String::length))
.collect(Collectors.toList());
6. peek(Consumer)
对每个元素执行操作(用于调试)。
List<String> result = names.stream()
.peek(System.out::println)
.collect(Collectors.toList());
四、常用终止操作详解
1. collect(Collectors.toList())
收集流元素为列表、集合或映射。
List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
Map<String, Integer> map = stream.collect(Collectors.toMap(...));
2. forEach(Consumer)
对每个元素执行操作。
names.stream().forEach(System.out::println);
3. count()
统计元素数量。
long count = names.stream().filter(name -> name.length() > 3).count();
4. anyMatch
, allMatch
, noneMatch
判断集合中是否有/所有/无元素匹配某个条件。
boolean any = names.stream().anyMatch(name -> name.startsWith("A"));
boolean all = names.stream().allMatch(name -> name.length() > 2);
boolean none = names.stream().noneMatch(name -> name.equals("Bob"));
5. findFirst()
, findAny()
返回流中第一个/任意一个元素(包装成 Optional
)。
Optional<String> first = names.stream().findFirst();
五、流的高级用法
1. 分组 Collectors.groupingBy
Map<Integer, List<String>> grouped = names.stream()
.collect(Collectors.groupingBy(String::length));
将字符串按长度分组。
2. 分区 Collectors.partitioningBy
Map<Boolean, List<String>> partitioned = names.stream()
.collect(Collectors.partitioningBy(name -> name.length() > 3));
按是否大于3个字符进行分区。
3. 统计信息 Collectors.summarizingInt
IntSummaryStatistics stats = names.stream()
.collect(Collectors.summarizingInt(String::length));
输出包括最大值、最小值、平均值、总和、个数。
六、并行流
通过 .parallelStream()
可以并行处理数据,提升多核处理效率。
List<Integer> numbers = IntStream.range(1, 1_000_000).boxed().collect(Collectors.toList());
long sum = numbers.parallelStream()
.mapToLong(Integer::longValue)
.sum();
注意:并行流适用于无共享状态的数据处理,线程安全要谨慎。
七、注意事项
- 流只能消费一次;
- 使用
peek()
主要用于调试,不推荐做副作用操作; -
map()
和flatMap()
要区分用途; - 对大数据量的集合操作,尽量使用并行流;
- Stream 不建议替代所有循环,过度使用会降低代码可读性。
八、总结
本文系统梳理了 Java 中流的基本原理和常用操作,包括:
- 中间操作如
filter
,map
,sorted
,flatMap
,distinct
等; - 终止操作如
collect
,forEach
,count
,findFirst
,anyMatch
等; - 分组分区、聚合统计等高级用法;
- 并行流的基本概念和使用建议。
通过流式编程,Java 的集合处理变得更强大、更优雅。在开发过程中,掌握 Stream API 可以大大提升你的代码质量和开发效率。希望这篇文章能帮助你理解并灵活运用 Java 的流处理方式。
???? 欢迎交流探讨,评论区见!