Java Stream API 常用方法速查
Java 8 引入的声明式集合处理工具。核心思想:用链式操作替代 for 循环。
基础概念
1 2 3 4 5 6
| List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream() .filter(s -> s.length() > 3) .map(String::toUpperCase) .collect(Collectors.toList());
|
| 概念 |
说明 |
| 中间操作 |
返回新 Stream,可继续链式调用。惰性,不调终端操作不执行 |
| 终端操作 |
触发整条链执行,返回最终结果。一个 Stream 只能有一个终端操作 |
| 惰性求值 |
中间操作只是声明”要做什么”,直到终端操作才真正执行 |
创建流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| List<String> list = Arrays.asList("a", "b", "c"); Stream<String> s1 = list.stream();
String[] arr = {"a", "b", "c"}; Stream<String> s2 = Arrays.stream(arr);
Stream<String> s3 = Stream.of("a", "b", "c");
Stream<String> s4 = Stream.empty();
Stream<Integer> s5 = Stream.iterate(0, n -> n + 2); Stream<Double> s6 = Stream.generate(Math::random);
IntStream.range(1, 5); IntStream.rangeClosed(1, 5);
|
中间操作
filter — 筛选
保留满足条件的元素。
1 2 3 4 5 6 7 8 9 10 11 12
| List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
nums.stream() .filter(n -> n > 3) .collect(Collectors.toList());
nums.stream() .filter(n -> n > 2 && n < 6) .collect(Collectors.toList());
|
map — 逐个变换
对每个元素应用函数,返回变换后的新流。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| List<String> names = Arrays.asList("alice", "bob", "charlie");
names.stream() .map(String::toUpperCase) .collect(Collectors.toList());
names.stream() .map(String::length) .collect(Collectors.toList());
users.stream() .map(User::getName) .collect(Collectors.toList());
|
flatMap — 拍平嵌套
每个元素映射为一个流,然后合并成一个流。解决 Stream<Stream<T>> 嵌套问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| List<User> users = ...;
users.stream().map(User::getOrders);
users.stream() .flatMap(u -> u.getOrders().stream()) .collect(Collectors.toList());
List<String> lines = Arrays.asList("hello world", "foo bar"); lines.stream() .flatMap(line -> Arrays.stream(line.split(" "))) .collect(Collectors.toList());
|
sorted — 排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| List<Integer> nums = Arrays.asList(3, 1, 4, 1, 5);
nums.stream().sorted().collect(Collectors.toList());
nums.stream() .sorted(Comparator.reverseOrder()) .collect(Collectors.toList());
users.stream() .sorted(Comparator.comparing(User::getAge)) .sorted(Comparator.comparing(User::getAge).reversed()) .collect(Collectors.toList());
|
distinct — 去重
1 2 3 4
| Arrays.asList(1, 1, 2, 2, 3).stream() .distinct() .collect(Collectors.toList());
|
limit / skip — 截取
1 2 3 4 5
| Stream.of(1, 2, 3, 4, 5) .skip(2) .limit(2) .collect(Collectors.toList());
|
peek — 查看(调试用)
不改变流,只是”偷看”每个元素,常用于调试。
1 2 3 4 5 6
| nums.stream() .filter(n -> n > 2) .peek(n -> System.out.println("过滤后: " + n)) .map(n -> n * 10) .peek(n -> System.out.println("变换后: " + n)) .collect(Collectors.toList());
|
终端操作
collect — 收集结果
最常用的终端操作,把流转成集合或其他数据结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| stream.collect(Collectors.toList());
stream.collect(Collectors.toSet());
users.stream().collect(Collectors.toMap( User::getId, User::getName ));
names.stream().collect(Collectors.joining(", "));
users.stream().collect(Collectors.groupingBy(User::getDepartment));
users.stream().collect(Collectors.partitioningBy(u -> u.getAge() > 30));
|
forEach — 逐个消费
1 2 3
| names.stream().forEach(System.out::println);
|
reduce — 聚合成单个值
1 2 3 4 5 6 7 8 9 10
| List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
nums.stream().reduce(0, Integer::sum);
nums.stream().reduce(Integer::max);
names.stream().reduce("", (a, b) -> a + b);
|
reduce 执行过程:
1 2 3 4 5 6 7 8
| reduce(0, Integer::sum)
初始值: 0 第1步: 0 + 1 = 1 第2步: 1 + 2 = 3 第3步: 3 + 3 = 6 第4步: 6 + 4 = 10 第5步: 10 + 5 = 15
|
count / min / max — 聚合统计
1 2 3 4
| long count = nums.stream().filter(n -> n > 3).count();
Optional<Integer> max = nums.stream().max(Integer::compareTo); Optional<Integer> min = nums.stream().min(Integer::compareTo);
|
anyMatch / allMatch / noneMatch — 条件判断
1 2 3 4 5
| List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
nums.stream().anyMatch(n -> n > 4); nums.stream().allMatch(n -> n > 0); nums.stream().noneMatch(n -> n > 10);
|
findFirst / findAny — 取元素
1 2 3 4 5 6 7 8
| Optional<String> first = names.stream() .filter(s -> s.startsWith("A")) .findFirst();
Optional<String> any = names.parallelStream() .filter(s -> s.length() > 3) .findAny();
|
toArray — 转数组
1 2 3
| String[] arr = names.stream() .filter(s -> s.length() > 3) .toArray(String[]::new);
|
数值流(避免装箱开销)
处理基本类型时,用专用流避免 int ↔ Integer 的自动装箱。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| int sum = IntStream.rangeClosed(1, 100).sum();
double avg = users.stream() .mapToInt(User::getAge) .average() .orElse(0);
IntStream.of(1, 2, 3, 4, 5).sum(); IntStream.of(1, 2, 3, 4, 5).average(); IntStream.of(1, 2, 3, 4, 5).summaryStatistics();
|
并行流
1 2 3 4 5 6 7 8
| list.stream().map(...).collect(...);
list.parallelStream().map(...).collect(...);
list.stream().parallel().map(...).collect(...);
|
注意事项:
- 数据量小(< 1万)时并行流反而更慢(线程调度开销)
- 操作必须是无状态的,不能依赖共享变量
ArrayList 并行性能好(随机访问),LinkedList 差(顺序访问)
实战组合示例
1. 统计词频
1 2 3 4 5 6 7 8
| String text = "hello world hello java world hello";
Map<String, Long> wordCount = Arrays.stream(text.split(" ")) .collect(Collectors.groupingBy( w -> w, Collectors.counting() ));
|
2. 取每个部门薪资最高的员工
1 2 3 4 5
| Map<String, Optional<Employee>> topByDept = employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.maxBy(Comparator.comparing(Employee::getSalary)) ));
|
3. 嵌套对象提取 + 去重
1 2 3 4 5 6 7
| List<String> productNames = orders.stream() .flatMap(order -> order.getItems().stream()) .map(Item::getProductName) .distinct() .sorted() .collect(Collectors.toList());
|
4. 分页查询
1 2 3 4 5
| List<User> page = users.stream() .sorted(Comparator.comparing(User::getCreatedAt).reversed()) .skip((pageNum - 1) * pageSize) .limit(pageSize) .collect(Collectors.toList());
|
5. CSV 行解析
1 2 3 4 5
| List<String[]> rows = Files.lines(Path.of("data.csv")) .skip(1) .map(line -> line.split(",")) .filter(cols -> cols.length >= 3) .collect(Collectors.toList());
|
速查表
| 操作 |
类型 |
签名 |
用途 |
filter |
中间 |
Stream<T> → Stream<T> |
筛选 |
map |
中间 |
Stream<T> → Stream<R> |
逐个变换 |
flatMap |
中间 |
Stream<T> → Stream<R> |
拍平嵌套 |
sorted |
中间 |
Stream<T> → Stream<T> |
排序 |
distinct |
中间 |
Stream<T> → Stream<T> |
去重 |
limit |
中间 |
Stream<T> → Stream<T> |
取前 N 个 |
skip |
中间 |
Stream<T> → Stream<T> |
跳过前 N 个 |
peek |
中间 |
Stream<T> → Stream<T> |
调试查看 |
collect |
终端 |
Stream<T> → R |
收集为集合 |
forEach |
终端 |
Stream<T> → void |
逐个消费 |
reduce |
终端 |
Stream<T> → T |
聚合成单值 |
count |
终端 |
Stream<T> → long |
计数 |
min/max |
终端 |
Stream<T> → Optional<T> |
最小/最大 |
anyMatch |
终端 |
Stream<T> → boolean |
存在匹配 |
allMatch |
终端 |
Stream<T> → boolean |
全部匹配 |
findFirst |
终端 |
Stream<T> → Optional<T> |
取第一个 |
toArray |
终端 |
Stream<T> → T[] |
转数组 |