电商分类统计需精准分组:按商品类别用summarizingDouble一次获取总额、均值、订单数;多级交叉用嵌套groupingBy实现“城市×年龄段×会员等级”;时间分组须先归一化并转业务时区;用户行为分组后可用collectingAndThen排序或toMap去重。

用 Collectors.groupingBy 做电商分类变量统计,关键不是“会不会分组”,而是“分得准、聚得实、看得清”。它不是简单把数据按字段切开,而是围绕业务目标,把用户、商品、订单、行为等维度的分类变量转化为可决策的分布规律。
按商品类别聚合销售核心指标
不能只统计数量,要一次拿到总额、均值、订单数等多维信息。用 summarizingDouble 替代多次 summingDouble + counting:
-
写法示例:
orders.stream().collect(groupingBy(Order::getCategory, summarizingDouble(Order::getAmount))) - 返回的是
DoubleSummaryStatistics对象,直接调用getSum()、getAverage()、getCount()即可 - 比嵌套多个下游收集器更简洁,也避免重复遍历
按用户画像做多级交叉分布
单一分组(如只看城市)意义有限,真实分析常需“城市 × 年龄段 × 会员等级”组合。用嵌套 groupingBy 实现自然层级:
-
写法示例:
users.stream().filter(User::isActive).collect(groupingBy(User::getCity, groupingBy(u -> u.getAge()/10*10 + "s", groupingBy(User::getLevel, counting())))) - 外层是城市,中层是年龄段(如 “20s”、“30s”),内层是会员等级(如 “GOLD”、“PLATINUM”),值为对应人数
- 注意:年龄分段逻辑要统一,避免
25 → 20s和29 → 20s不一致
按时间区间归一化后分组统计趋势
原始时间戳无法直接分组,必须先“打标”成逻辑时段。重点在归一化方式是否贴合业务节奏:
-
按小时档位(如每2小时一档):
o -> o.getCreateTime().withMinute(0).withSecond(0).withNano(0).minusHours(o.getCreateTime().getHour() % 2) -
按自然周(周一 00:00 起):
o -> o.getCreateTime().with(DayOfWeek.MONDAY).truncatedTo(DAYS) - 务必先转业务时区:
o.getCreateTime().withZoneSameInstant(ZoneId.of("Asia/Shanghai")).toLocalDateTime(),再截断,否则跨日统计会错位
按操作行为汇总用户轨迹并做轻加工
不只是分组存列表,还要支持常见后处理——排序、去重、抽样,用 collectingAndThen 封装逻辑:
-
按用户ID分组 + 按时间倒序排列: 下游用
collectingAndThen(toList(), list -> list.stream().sorted(comparing(OperationLog::getTime).reversed()).collect(toList())) -
按用户ID分组 + 去重保留最新一次操作: 可改用
toMap收集器替代toList,以时间为 value,自动覆盖旧记录 - null 值必须显式处理,例如
log -> log.getUserId() != null ? log.getUserId() : 0L,否则流中断










