一、Stream流的核心概念
什么是Stream流
- Java 8引入的函数式数据处理API,用于高效操作集合(Collection)、数组等数据源
- 不是数据结构,不存储数据,而是通过管道操作处理数据源
- 支持链式调用 和惰性求值(Lazy Evaluation)
核心特点
- 无存储:不修改原始数据源
- 函数式风格:支持Lambda表达式
- 延迟执行:中间操作不会立即执行
- 可消费性:流只能被使用一次
- 声明式:更关注"做什么"而非"如何做"
- 链式调用:通过方法链组合多个操作
Stream的组成
- 数据源:集合、数组、I/O资源等
- 中间操作:过滤、映射、排序等(返回新的Stream)
- 终端操作:触发计算并产生结果(如collect、forEach等)
操作类型
类型 |
方法示例 |
特点 |
中间操作 |
filter() , map() , sorted() |
返回新Stream,可链式调用 |
终止操作 |
forEach() , collect() , count() |
触发计算,流被消耗 |
二、Stream流使用全流程
1.Stream流的创建
从集合创建
java
复制代码
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> streamFromList = list.stream();
从数组创建
java
复制代码
String[] array = {"a", "b", "c"};
Stream<String> streamFromArray = Arrays.stream(array);
直接创建
java
复制代码
Stream<String> directStream = Stream.of("a", "b", "c");
2.常用中间操作
操作 |
说明 |
示例 |
filter() |
条件过滤 |
.filter(s -> s.contains("a")) |
map() |
元素转换 |
.map(String::length) |
flatMap() |
扁平化转换(合并流) |
.flatMap(list -> list.stream()) |
distinct() |
去重 |
.distinct() |
sorted() |
排序 |
.sorted(Comparator.reverseOrder()) |
peek() |
调试用(不修改元素) |
.peek(System.out::println) |
过滤和限制
java
复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 过滤以"A"开头的名字
List<String> result = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList()); // [Alice]
// 限制返回数量
List<String> limited = names.stream()
.limit(2)
.collect(Collectors.toList()); // [Alice, Bob]
映射
java
复制代码
List<String> words = Arrays.asList("Java", "Stream", "API");
// 转换为字符串长度
List<Integer> lengths = words.stream()
.map(String::length)
.collect(Collectors.toList()); // [4, 6, 3]
// 扁平化流(flatMap)
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("a", "b"),
Arrays.asList("c", "d")
);
List<String> flatList = nestedList.stream()
.flatMap(List::stream)
.collect(Collectors.toList()); // [a, b, c, d]
排序
java
复制代码
List<String> names = Arrays.asList("John", "Alice", "Bob", "Charlie");
// 自然排序
List<String> sorted = names.stream()
.sorted()
.collect(Collectors.toList()); // [Alice, Bob, Charlie, John]
// 自定义排序
List<String> customSorted = names.stream()
.sorted((s1, s2) -> s2.compareTo(s1))
.collect(Collectors.toList()); // [John, Charlie, Bob, Alice]
去重
java
复制代码
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4);
List<Integer> distinct = numbers.stream()
.distinct()
.collect(Collectors.toList()); // [1, 2, 3, 4]
3.常用终止操作
操作 |
说明 |
示例 |
forEach() |
遍历 |
.forEach(System.out::println) |
collect() |
转换为集合 |
.collect(Collectors.toList()) |
toArray() |
转换为数组 |
.toArray(String[]::new) |
reduce() |
聚合计算 |
.reduce(0, Integer::sum) |
min()/max() |
极值查找 |
.max(Comparator.naturalOrder()) |
count() |
计数 |
.count() |
anyMatch() |
任意元素匹配 |
.anyMatch(s -> s.startsWith("A")) |
收集结果
java
复制代码
List<String> collected = Stream.of("a", "b", "c")
.collect(Collectors.toList()); // [a, b, c]
Set<String> collectedSet = Stream.of("a", "b", "c")
.collect(Collectors.toSet()); // [a, b, c] (顺序可能不同)
String joined = Stream.of("a", "b", "c")
.collect(Collectors.joining(", ")); // "a, b, c"
遍历
java
复制代码
Stream.of("a", "b", "c")
.forEach(System.out::println); // 打印每个元素
匹配
java
复制代码
boolean anyStartsWithA = Stream.of("apple", "banana", "apricot")
.anyMatch(s -> s.startsWith("a")); // true
boolean allStartsWithA = Stream.of("apple", "apricot", "avocado")
.allMatch(s -> s.startsWith("a")); // true
boolean noneStartsWithZ = Stream.of("apple", "banana", "cherry")
.noneMatch(s -> s.startsWith("z")); // true
四、实战技巧与最佳实践
避免嵌套循环
java
复制代码
// 传统方式
for (Order order : orders) {
for (Item item : order.getItems()) {
if (item.isActive()) {
activeItems.add(item);
}
}
}
// Stream优化
List<Item> activeItems = orders.stream()
.flatMap(order -> order.getItems().stream())
.filter(Item::isActive)
.collect(Collectors.toList());
并行流加速处理
java
复制代码
long count = largeList.parallelStream() // 使用多核并行处理
.filter(obj -> obj.getValue() > 100)
.count();
短路优化性能
java
复制代码
boolean hasAdmin = users.stream()
.anyMatch(user -> "admin".equals(user.getRole())); // 找到即终止
分组与分区
java
复制代码
// 按年龄分组
Map<Integer, List<Person>> ageGroups = people.stream()
.collect(Collectors.groupingBy(Person::getAge));
// 分区:年龄是否>=18
Map<Boolean, List<Person>> adults = people.stream()
.collect(Collectors.partitioningBy(p -> p.getAge() >= 18));
自定义收集器
java
复制代码
// 拼接字符串
String joined = stream.collect(Collectors.joining(", ", "[", "]"));
通过掌握Stream API,可使代码简洁性提升50%+,同时利用并行流可大幅提升大数据处理效率。重点理解操作链的惰性求值特性 和流的一次性消费原则,避免常见陷阱。