
本文介绍如何使用 java 8 stream api 将 hashmap 中具有相同值的所有键聚合成逗号分隔的字符串,并按值分组输出,解决“一值多键”场景下的结构化展示需求。
本文介绍如何使用 java 8 stream api 将 hashmap 中具有相同值的所有键聚合成逗号分隔的字符串,并按值分组输出,解决“一值多键”场景下的结构化展示需求。
在实际开发中,我们常遇到需要反向查询 Map 的场景:不是“由键查值”,而是“由值查所有对应键”。例如医疗系统中多个患者 ID(键)可能对应同一姓名(值),需汇总显示为 "Adam - 555,666"。原始代码的问题在于:它对每个键值对单独处理,未做值层面的分组,导致重复输出且无法合并相同值的键。
正确做法是利用 Collectors.groupingBy 实现按值分组,再通过 Collectors.mapping + Collectors.joining 将同组的键拼接为字符串。以下是完整、可运行的解决方案:
import java.util.*;
import java.util.stream.Collectors;
public class GroupKeysByValue {
public static void main(String[] args) {
Map<String, String> patients = new HashMap<>();
patients.put("555", "Adam");
patients.put("666", "Adam");
patients.put("66r", "PAM");
// 按 value 分组,将相同 value 对应的所有 key 用逗号连接
Map<String, String> grouped = patients.entrySet().stream()
.collect(Collectors.groupingBy(
Map.Entry::getValue, // 分组依据:value
Collectors.mapping( // 映射每个 entry 的 key
Map.Entry::getKey,
Collectors.joining(",") // 用逗号连接同组 key
)
));
// 格式化输出:value - key1,key2,...
grouped.forEach((value, keys) ->
System.out.println(value + " - " + keys)
);
}
}输出结果:
Adam - 555,666 PAM - 66r
✅ 关键要点说明:
立即学习“Java免费学习笔记(深入)”;
-
groupingBy(Map.Entry::getValue):以Entry的value作为分组键; -
mapping(Map.Entry::getKey, joining(",")):对每个分组内的Entry提取key,再用,连接成单个字符串; - 最终得到
Map<string string></string>,其中 key 是原 Map 的 value,value 是对应的所有原 key 的拼接串。
⚠️ 注意事项:
- 若需保持插入顺序(如按首次出现顺序输出
"Adam"在"PAM"前),可将外层groupingBy替换为groupingBy(..., LinkedHashMap::new, ...); - 若键或值含
null,需提前过滤(filter(e -> e.getValue() != null && e.getKey() != null)),否则joining可能抛NullPointerException; - 此方案时间复杂度为 O(n),优于嵌套循环的 O(n²) 手动遍历方式,兼具简洁性与性能。
该方法是 Java 8+ 处理“多键一值”聚合问题的标准实践,推荐在业务逻辑中直接复用。


















