Java Stream 业务操作手册
本文整理了日常开发中最常见的 Java Stream 操作,结合业务场景,按功能分类,可直接复制到项目中使用。
目录
- 数据准备
- 合并与去重
- List → Map 转换
- 分组与多级分组
- 聚合与统计
- 对象属性合并(按 ID 合并等)
- 过滤与条件查询
- 排序
- 扁平化处理
- 条件统计与布尔判断
- 复杂聚合(一次性获取多指标)
- 分页与截取
- 高级技巧(字段去重、并发流等)
1. 数据准备
@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
private Long id;
private String name;
private String city;
private int age;
private int score;
}
List<User> users = Arrays.asList(
new User(1L, "Tom", "Beijing", 25, 90),
new User(1L, "Tom", "Beijing", 25, 70),
new User(2L, "Jerry", "Shanghai", 30, 85),
new User(3L, "Alice", "Beijing", 28, 95),
new User(4L, "Bob", "Guangzhou", 26, 60)
);
2. 合并与去重
合并两个 List 并去重
List<String> list1 = Arrays.asList("A", "B");
List<String> list2 = Arrays.asList("B", "C");
List<String> merged = Stream.concat(list1.stream(), list2.stream())
.distinct()
.collect(Collectors.toList());
业务场景:两个接口返回的数据集合,需要合并成唯一集合。
3. List → Map 转换
基本转换
Map<Long, String> userMap = users.stream()
.collect(Collectors.toMap(User::getId, User::getName, (v1, v2) -> v1));
对象本身作为值
Map<Long, User> userObjMap = users.stream()
.collect(Collectors.toMap(User::getId, Function.identity(), (u1, u2) -> u1));
业务场景:快速通过 ID 获取对象或属性。
4. 分组与多级分组
按单字段分组
Map<String, List<User>> groupByCity = users.stream()
.collect(Collectors.groupingBy(User::getCity));
多级分组(城市 → 年龄)
Map<String, Map<Integer, List<User>>> groupByCityAndAge =
users.stream()
.collect(Collectors.groupingBy(User::getCity,
Collectors.groupingBy(User::getAge)));
业务场景:报表类需求,如“按部门 → 职级”分组。
5. 聚合与统计
分组求和
Map<String, Integer> totalScoreByCity = users.stream()
.collect(Collectors.groupingBy(
User::getCity,
Collectors.summingInt(User::getScore)
));
分组求平均
Map<String, Double> avgScoreByCity = users.stream()
.collect(Collectors.groupingBy(
User::getCity,
Collectors.averagingInt(User::getScore)
));
6. 对象属性合并(按 ID 合并等)
Map<Long, User> mergedById = users.stream()
.collect(Collectors.toMap(
User::getId,
u -> new User(u.getId(), u.getName(), u.getCity(), u.getAge(), u.getScore()),
(u1, u2) -> {
u1.setScore(u1.getScore() + u2.getScore()); // 累加分数
return u1;
}
));
List<User> mergedList = new ArrayList<>(mergedById.values());
业务场景:多条同一用户记录,合并金额、积分等。
7. 过滤与条件查询
单条件
List<User> highScore = users.stream()
.filter(u -> u.getScore() > 80)
.collect(Collectors.toList());
多条件
List<User> beijingHighScore = users.stream()
.filter(u -> "Beijing".equals(u.getCity()) && u.getScore() > 80)
.collect(Collectors.toList());
8. 排序
单字段排序(降序)
List<User> sortedByScore = users.stream()
.sorted(Comparator.comparing(User::getScore).reversed())
.collect(Collectors.toList());
多字段排序
List<User> sorted = users.stream()
.sorted(Comparator.comparing(User::getCity)
.thenComparing(User::getScore, Comparator.reverseOrder()))
.collect(Collectors.toList());
9. 扁平化处理
List<List<String>> nested = Arrays.asList(
Arrays.asList("A", "B"),
Arrays.asList("C", "D")
);
List<String> flatList = nested.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
业务场景:接口返回嵌套数据,需拍平。
10. 条件统计与布尔判断
计数
long count = users.stream().filter(u -> u.getScore() > 80).count();
是否存在符合条件
boolean exists = users.stream().anyMatch(u -> u.getScore() == 100);
是否全部符合条件
boolean allPass = users.stream().allMatch(u -> u.getScore() >= 60);
11. 复杂聚合(一次性获取多指标)
Map<String, IntSummaryStatistics> statsByCity = users.stream()
.collect(Collectors.groupingBy(
User::getCity,
Collectors.summarizingInt(User::getScore)
));
IntSummaryStatistics beijingStats = statsByCity.get("Beijing");
// beijingStats.getSum() / getAverage() / getMax() / getMin()
12. 分页与截取
List<User> page1 = users.stream()
.skip(0) // 跳过 0 条
.limit(2) // 取 2 条
.collect(Collectors.toList());
业务场景:内存分页。
13. 高级技巧
按字段去重
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
List<User> distinctUsers = users.stream()
.filter(distinctByKey(User::getId))
.collect(Collectors.toList());
并行流
List<String> result = users.parallelStream()
.map(User::getName)
.collect(Collectors.toList());
注意:并行流适合 CPU 密集型计算,大数据量时加速效果明显,但需要考虑线程安全。