Java中用HashMap嵌套ArrayList实现分组统计,核心是将分组依据作键、同组元素存入ArrayList作值;需用computeIfAbsent确保键对应非空列表,避免覆盖或空指针;支持按字段分组、数量统计、聚合计算及不可变封装,亦可用Stream API简化。

Java 中用 HashMap 嵌套 ArrayList 实现分组统计,核心是把“分组依据”作为 HashMap 的键(K),把属于同一组的元素存进 ArrayList 作为值(V)。这不是单纯“嵌套”,而是利用 HashMap<k arraylist>></k> 的结构做动态分组。
初始化 Map 并确保每个 key 对应一个非空 ArrayList
不能直接 put 新的 ArrayList,否则重复 key 会覆盖旧列表。推荐在每次添加前检查 key 是否存在,不存在就新建一个空列表:
Map<String, ArrayList<Integer>> groupMap = new HashMap<>();
for (int num : numbers) {
String category = getCategory(num); // 比如 num > 0 ? "positive" : "non-positive"
groupMap.computeIfAbsent(category, k -> new ArrayList<>()).add(num);
}
computeIfAbsent 是最简洁安全的方式:key 不存在时自动创建新 ArrayList 并返回,存在则直接返回原列表,避免空指针和重复 new。
按对象字段分组(常见业务场景)
比如有一组 User 对象,想按城市分组:
立即学习“Java免费学习笔记(深入)”;
class User { String name; int age; String city; }
List<User> users = ...;
Map<String, ArrayList<User>> byCity = new HashMap<>();
for (User u : users) {
byCity.computeIfAbsent(u.city, k -> new ArrayList<>()).add(u);
}
// 结果:byCity.get("Beijing") 返回所有北京用户的 ArrayList
注意:如果 city 可能为 null,需提前处理,否则 computeIfAbsent 会抛 NullPointerException。可统一转成字符串(如 Objects.toString(u.city, "unknown"))。
统计每组数量或进一步聚合
分组后常需知道每组大小,或计算平均值、总和等。可直接操作 value 列表:
- 获取每组人数:
byCity.get("Shanghai").size() - 求每组年龄总和:
byCity.get("Shanghai").stream().mapToInt(u -> u.age).sum() - 转成不可变副本(避免外部修改):
Collections.unmodifiableList(byCity.get("Shanghai"))
替代方案:用 Stream API 一行搞定(Java 8+)
如果只是简单分组,用 Collectors.groupingBy 更直观:
Map<String, List<User>> byCity2 = users.stream()
.collect(Collectors.groupingBy(u -> u.city));
// 注意:默认返回的是 List,不是 ArrayList;如需 ArrayList,加个 mapping:
Map<String, ArrayList<User>> byCity3 = users.stream()
.collect(Collectors.groupingBy(
u -> u.city,
Collectors.toCollection(ArrayList::new)
));
Stream 方式代码更短,适合一次性分组;而手动遍历 + computeIfAbsent 更灵活,适合边处理边分组、或需要中间逻辑判断的场景。


















