HashMap过滤时输出不符合预期的问题排查
为什么传入多个参数时HashMap过滤结果会丢失部分条目?
我现在有个需求:用命令行传入多个源系统名称(比如SSN1、SSN2),从一个HashMap里过滤出包含这些名称的键值对,并且每个匹配的源系统都要单独输出对应的表项。
我的HashMap结构是键为源表名,值的格式是"目标表名:ssn1,ssn2,...",比如("Table1", "Table1:SSN1,SSN2,SSN3,SSN4,SSN5")。
我写了这段Java代码:
import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; public class FilterKeyValues { public static void main(String[] args) { String[] valArr; String ky; Map<String, String> hmap = new HashMap<String, String>(); Map<String, String> filtered = new HashMap<String, String>(); hmap.put("Table1", "Table1:SSN1,SSN2,SSN3,SSN4,SSN5"); hmap.put("Table2", "Table2:SSN1,SSN4,SSN2,SSN5,SSN8,SSN9,SSN10"); hmap.put("Table3", "Table3:SSN4,SSN1"); hmap.put("Table4", "Table4:SSN5,SSN6,SSN7"); hmap.put("Table5", "Table5:SSN8,SSN1,SSN5,SSN2"); if(args.length > 0) { for(String ssname: args) { for (Entry<String, String> entry : hmap.entrySet()) { if (entry.getValue().contains(ssname)) { ky = entry.getKey(); valArr = entry.getValue().split(":"); filtered.put(ky, valArr[0]+":"+ssname); } } } } for (String iter: filtered.keySet()){ String key = iter.toString(); String value = filtered.get(key).toString(); System.out.println(key + "->" + value); } } }
当我传入参数SSN1 SSN2时,预期输出是:
Table1->Table1:SSN1 Table2->Table2:SSN1 Table3->Table3:SSN1 Table5->Table5:SSN1 Table1->Table1:SSN2 Table2->Table2:SSN2 Table5->Table5:SSN2
但实际得到的输出却是:
Table2->Table2:SSN2 Table3->Table3:SSN1 Table5->Table5:SSN2 Table1->Table1:SSN2
我实在找不到问题出在哪,有人能帮我看看吗?
问题根源:HashMap的键唯一性导致覆盖
你的问题出在**filtered这个HashMap的特性上**——HashMap的键是唯一的,当你多次对同一个键调用put()方法时,新的值会直接覆盖旧的值。
举个具体的执行流程:
- 循环第一个参数
SSN1时,你会把Table1->Table1:SSN1放入filtered; - 接着循环第二个参数
SSN2时,发现Table1也包含SSN2,于是再次执行filtered.put("Table1", "Table1:SSN2"),这就把之前存储的Table1:SSN1给覆盖掉了。
同理,Table2和Table5也会被最后一次匹配的SSN2覆盖,只有Table3因为只匹配SSN1,所以保留了下来。这就是为什么你看不到所有预期的条目。
解决方案:改用合适的数据结构存储结果
要实现你的预期输出,你需要一个能为同一个表名存储多个匹配结果的结构,这里提供两种常用方案:
方案1:用List存储所有匹配的条目(最简单直接)
把filtered从Map<String, String>改成List<String>,每次匹配成功就把key->value的字符串直接加入列表:
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class FilterKeyValues { public static void main(String[] args) { String[] valArr; Map<String, String> hmap = new HashMap<String, String>(); List<String> filtered = new ArrayList<>(); // 替换为List hmap.put("Table1", "Table1:SSN1,SSN2,SSN3,SSN4,SSN5"); hmap.put("Table2", "Table2:SSN1,SSN4,SSN2,SSN5,SSN8,SSN9,SSN10"); hmap.put("Table3", "Table3:SSN4,SSN1"); hmap.put("Table4", "Table4:SSN5,SSN6,SSN7"); hmap.put("Table5", "Table5:SSN8,SSN1,SSN5,SSN2"); if(args.length > 0) { for(String ssname: args) { for (Entry<String, String> entry : hmap.entrySet()) { if (entry.getValue().contains(ssname)) { valArr = entry.getValue().split(":"); filtered.add(entry.getKey() + "->" + valArr[0] + ":" + ssname); } } } } // 直接遍历List输出所有结果 for (String result : filtered) { System.out.println(result); } } }
方案2:用Map<String, List>分组存储(更灵活)
如果你需要后续对每个表的匹配结果做进一步处理,可以用Map<String, List<String>>,键是表名,值是该表匹配的所有SSN列表:
import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.ArrayList; public class FilterKeyValues { public static void main(String[] args) { String[] valArr; Map<String, String> hmap = new HashMap<String, String>(); Map<String, List<String>> filtered = new HashMap<>(); // 分组存储结构 hmap.put("Table1", "Table1:SSN1,SSN2,SSN3,SSN4,SSN5"); hmap.put("Table2", "Table2:SSN1,SSN4,SSN2,SSN5,SSN8,SSN9,SSN10"); hmap.put("Table3", "Table3:SSN4,SSN1"); hmap.put("Table4", "Table4:SSN5,SSN6,SSN7"); hmap.put("Table5", "Table5:SSN8,SSN1,SSN5,SSN2"); if(args.length > 0) { for(String ssname: args) { for (Entry<String, String> entry : hmap.entrySet()) { if (entry.getValue().contains(ssname)) { String tableName = entry.getKey(); // 如果表名不在Map里,先初始化一个空列表 filtered.computeIfAbsent(tableName, k -> new ArrayList<>()); filtered.get(tableName).add(ssname); } } } } // 遍历输出,每个表的每个SSN单独一行 for (Entry<String, List<String>> entry : filtered.entrySet()) { String table = entry.getKey(); for (String ssn : entry.getValue()) { System.out.println(table + "->" + table + ":" + ssn); } } } }
这两种方案都能得到你预期的输出结果,你可以根据自己的后续需求选择合适的方式。
内容的提问来源于stack exchange,提问作者Metadata
相关产品推荐
相关产品推荐

