一、stream流介绍
在Java8之后,Java新增了java.util.stream
包,它允许你以声明式的方式处理集合数据,使得代码更加的简介、更易读,同时提供了强大的处理能力。
stream是一种数据处理现象,它不是数据结构,而是从数据源(集合、数组)生成的元素序列,并支持各种聚合操作(过滤、映射、排序等)。stream的特点是:
(1)不存储数据:stream只是对数据源进行视图话操作,不改变原始数据。
(2)函数式编程:所有操作都是以函数式风格进行,支持lambda表达式。
(3)延迟执行:中间操作(如filter、map)不会立即执行、只有终止操作(如collect、forEach)才会触发计算。
(4)可消费性:stream只能被消费一次,消费后需要重新创建。
二、stream流的实践
1、stream的基本操作流程
(1)创建stream:从集合、数组等数据源获取stream。
(2)中间操作:对stream中的元素及进行转换或过滤,返回一个新的stream。
(3)终止操作:触发实际计算,产生结果(如集合、数值或副作用)。
示例代码:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 创建 Stream → 中间操作(过滤长度>4)→ 中间操作(转换为大写)→ 终止操作(收集结果)
List<String> result = names.stream()
.filter(name -> name.length() > 4)
.map(String::toUpperCase)
.collect(Collectors.toList());
// 结果:[ALICE, CHARLIE, DAVID]
2、中间操作
中间操作返回一个新的stream,对于元素进行转换或过滤。常见的中间操作:
操作 | 描述 | 实例 |
---|---|---|
filter | 过滤满足条件的元素 | stream.filter(num -> num > 10) |
map | 将元素转换为另一种类型 | stream.map(String::length) |
flatMap | 将嵌套的 Stream 展开为单个 Stream | stream.flatMap(list -> list.stream()) |
distinct | 去重(基于 equals 和 hashCode ) | stream.distinct() |
sorted | 排序(自然顺序或指定比较器) | stream.sorted((a, b) -> a.compareTo(b)) |
limit | 截断 Stream,返回前 n 个元素 | stream.limit(5) |
skip | 跳过前 n 个元素 | stream.skip(3) |
peek | 调试工具,对每个元素执行副作用(如打印) | stream.peek(System.out::println) |
3、终止操作
终止操作触发stream的执行并产生结果。常见的终止操作:
操作 | 描述 | 示例 |
---|---|---|
forEach | 遍历元素 | stream.forEach(System.out::println) |
collect | 将元素收集到集合或其他数据结构中 | stream.collect(Collectors.toList()) |
toArray | 将元素转换为数组 | stream.toArray(String[]::new) |
reduce | 聚合元素为单个值(如求和、求最大值) | stream.reduce(0, Integer::sum) |
count | 统计元素数量 | stream.count() |
anyMatch | 判断是否至少有一个元素满足条件 | stream.anyMatch(s -> s.contains("a")) |
allMatch | 判断所有元素是否都满足条件 | stream.allMatch(s -> s.length() > 0) |
noneMatch | 判断所有元素是否都不满足条件 | stream.noneMatch(s -> s.isEmpty()) |
findFirst | 返回第一个元素(可能为空,返回 Optional ) | stream.findFirst() |
findAny | 返回任意一个元素(并行流中可能随机返回) | stream.findAny() |
4、收集器(Collectors)
Collectors工具类提供了强大的聚合功能,用于将stream元素手机到各种数据结构中:
收集器 | 描述 | 示例 |
---|---|---|
toList() | 收集元素到 List 中 | stream.collect(Collectors.toList()) |
toSet() | 收集元素到 Set 中(自动去重) | stream.collect(Collectors.toSet()) |
toMap() | 收集元素到 Map 中(需指定键和值的映射) | stream.collect(Collectors.toMap(Person::getId, Person::getName)) |
groupingBy | 按条件分组,返回 Map<K, List<T>> | stream.collect(Collectors.groupingBy(Person::getDepartment)) |
partitioningBy | 按布尔条件分区,返回 Map<Boolean, List<T>> | stream.collect(Collectors.partitioningBy(p -> p.getAge() > 18)) |
joining | 连接字符串元素 | stream.collect(Collectors.joining(", ")) |
summingInt/Double/Long | 对数值类型求和 | stream.collect(Collectors.summingInt(Person::getAge)) |
averagingInt/Double/Long | 计算平均值 | stream.collect(Collectors.averagingDouble(Person::getScore)) |
maxBy/minBy | 求最大值 / 最小值(需传入比较器) | stream.collect(Collectors.maxBy(Comparator.comparing(Person::getAge))) |
5、并行流
stream支持并行处理,通过parallel()方法将顺序流转换为并行流,利用多核CPU提升性能:
// 顺序流:单线程处理
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sumSequential = numbers.stream()
.mapToInt(Integer::intValue)
.sum();
// 并行流:多线程处理(适用于大数据集)
int sumParallel = numbers.parallelStream()
.mapToInt(Integer::intValue)
.sum();
/**
*
*注意事项:
*1、并行流的线程安全问题(避免共享可变状态)。
*2、并非所有场景都适合并行(如小数据集或 IO 密集型操作)。
*3、使用 sequential() 方法可将并行流转回顺序流。
*
**/
结语:
掌握 Stream 流是现代 Java 开发的必备技能,它让代码更简洁、更具表现力,同时提升了开发效率和程序性能。