Collectors.groupingBy 可按用户属性分组并聚合操作行为:单属性用 counting() 统计次数;多属性用 SimpleEntry 封装键并 toList() 收集详情;分组后可用 averagingDouble 等做数值统计;预 filter 可高效实现条件筛选。

用 Collectors.groupingBy 按用户属性(如 userId、role、region)汇总操作行为详情,核心是把行为记录按指定字段分组,再对每组做聚合(如统计次数、收集列表、计算耗时均值等)。关键在于选对分类键、配合适当的下游收集器。
按单一属性分组并统计行为次数
最常见需求:统计每个用户做了多少次操作。
- 假设行为对象为
OperationLog,含userId和actionType字段 - 使用
groupingBy提取userId作为 key,下游用counting()统计数量
.collect(Collectors.groupingBy(OperationLog::getUserId, Collectors.counting()));
按多属性组合分组并收集行为详情列表
需保留原始行为记录(如查某地区 VIP 用户的所有登录日志)。
- 用
SimpleEntry或自定义键类封装多个属性(如 region + role) - 下游用
toList()收集每组全部日志 - 注意:键对象必须正确实现
equals和hashCode
.collect(Collectors.groupingBy(
log -> new AbstractMap.SimpleEntry(log.getRegion(), log.getRole()),
Collectors.toList()
));
分组后进一步聚合(如计算平均响应时间)
不仅分组,还要对每组内数值型字段做统计。
- 下游使用
Collectors.averagingDouble、summingLong或summarizingInt - 例如:按
actionType分组,求各操作类型的平均耗时
.collect(Collectors.groupingBy(
OperationLog::getActionType,
Collectors.averagingDouble(OperationLog::getDurationMs)
));
分组同时做条件过滤与映射(如只统计失败操作)
实际中常需先筛选再分组,避免在分组后遍历处理。
- 推荐在
stream()阶段用filter()预处理,再分组 - 若需分组内单独过滤(如每组只取最近 3 条),可用
mapping+ 自定义收集逻辑 - 简单场景:每组只收集失败日志 →
filter放在stream()上更清晰高效
.filter(log -> "FAILED".equals(log.getStatus()))
.collect(Collectors.groupingBy(OperationLog::getUserId, Collectors.toList()));

















