Java 8 引入的 Stream 是函数式编程的重要体现,能极大简化集合操作的复杂度。本文从基础用法到进阶技巧,全面梳理 Java Stream 的常见应用场景。


一、什么是 Stream?

Stream 是对集合(Collection)对象功能的增强,它不是数据结构,不会存储数据,而是以声明式方式对数据进行处理(类似 SQL 风格)。

Stream 特点:

  • 不修改原数据结构
  • 惰性求值(lazy evaluation)
  • 支持链式调用
  • 天然支持并行操作(parallelStream)

二、Stream 创建方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
List<String> list = Arrays.asList("apple", "banana", "orange");

// 从集合创建
Stream<String> stream1 = list.stream();

// 从数组创建
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4);

// 生成无限流(需限制)
Stream<Double> stream3 = Stream.generate(Math::random).limit(10);
````

---

## 三、常用操作(中间操作)

### 1. filter(过滤)

```java
list.stream()
.filter(s -> s.startsWith("a"))
.forEach(System.out::println);

2. map(映射)

1
2
3
List<Integer> lengths = list.stream()
.map(String::length)
.collect(Collectors.toList());

3. sorted(排序)

1
2
3
list.stream()
.sorted()
.forEach(System.out::println);

4. distinct(去重)

1
2
3
Stream.of(1, 2, 2, 3, 3)
.distinct()
.forEach(System.out::print); // 123

5. peek(调试用)

1
2
3
list.stream()
.peek(System.out::println)
.collect(Collectors.toList());

四、终结操作(终点)

1. collect(收集结果)

1
2
3
List<String> result = list.stream()
.filter(s -> s.length() > 5)
.collect(Collectors.toList());

2. count / anyMatch / allMatch / noneMatch

1
2
3
long count = list.stream().filter(s -> s.contains("a")).count();

boolean hasLong = list.stream().anyMatch(s -> s.length() > 10);

3. findFirst / findAny

1
Optional<String> first = list.stream().findFirst();

4. reduce(规约)

1
2
int sum = Stream.of(1, 2, 3, 4)
.reduce(0, Integer::sum); // 输出 10

五、进阶操作

1. 分组 & 统计

1
2
3
4
5
Map<Integer, List<String>> grouped = list.stream()
.collect(Collectors.groupingBy(String::length));

Map<String, Long> counted = list.stream()
.collect(Collectors.groupingBy(s -> s, Collectors.counting()));

2. flatMap(扁平化)

1
2
3
4
5
6
7
8
List<List<String>> nested = Arrays.asList(
Arrays.asList("A", "B"),
Arrays.asList("C", "D")
);

List<String> flat = nested.stream()
.flatMap(List::stream)
.collect(Collectors.toList());

3. 并行流(parallelStream)

1
2
3
list.parallelStream()
.map(String::toUpperCase)
.forEach(System.out::println);

注意:并行流适合 CPU 密集型、无状态的操作,慎用在小数据集或 I/O 场景。


六、自定义对象的使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class User {
String name;
int age;

// constructor, getters, toString ...
}

List<User> users = Arrays.asList(
new User("Alice", 20),
new User("Bob", 25),
new User("Charlie", 20)
);

// 按年龄分组
Map<Integer, List<User>> byAge = users.stream()
.collect(Collectors.groupingBy(User::getAge));

七、Stream 使用注意事项

  • Stream 只能使用一次,执行终结操作后不能再继续链式调用。
  • 惰性执行:中间操作不会立刻执行,直到触发终结操作。
  • 如果出现性能瓶颈或调试困难,可用 .peek() 或切换回传统方式测试。
  • 尽量避免在 stream 中使用可变状态(如外部变量累加等)。

Stream 是提升代码表达力和性能的利器,掌握之后,很多集合操作都能变得更简洁优雅。

如果你有更高级的 Stream 应用(如多级分组、嵌套规约、复杂 map-reduce 等),欢迎评论区继续交流讨论。