关于map的细节-map.get(Object key)为null

探讨了在Java中使用LinkedHashMap时遇到get()方法返回null的问题,深入分析了Location类的equals和hashCode方法对查找操作的影响,并通过重写hashCode方法解决了该问题。
  • 现象
    map.get(Object key)为null,我很确定这个key是我传进去并且自认为是与put进去的值相等。
  • 过程
    我有一个用于储存成绩信息的坐标(key)及成绩值(value)的LinkedHashMap:
private LinkedHashMap<Location, String> gradesMap = new LinkedHashMap<>();

Location类如下(为了篇幅,去掉了getter和setter方法):

public class Location {

        public Location(Integer row, Integer column) {
            this.row = row;
            this.column = column;
        }

        private Integer row;

        private Integer column;
        
        @Override
        public boolean equals(Object obj) {
            Location location = (Location) obj;
            return column.equals(location.getColumn()) && row.equals(location.getRow());
        }
     }

重写了equals是为了使得当Location两个属性分别相等时对象引用就相同。即形如locationA.equals(locationB)这种。我还做了测试:

		Location a = new Location(1,1);
        Location b = new Location(1,1);
        LOGGER.info("相等不:{}", a.equals(b));

输出结果为true。
这里是为了解析如下图所示的excel里面的数据使用:
学生课程成绩信息
按行解析后,将在这里插入图片描述
最后按照预想的做法取出map中的值:
在这里插入图片描述
结果发现这个value始终为null。
很不甘心,又做了个实验:
在这里插入图片描述
输入结果也为null,这时候开始怀疑人生了,按道理说,key都是同一个了,为啥获取到值还是空的。于是就去翻这个map.get(Object key)方法:
在这里插入图片描述
这是LinkedHashMap中的get方法源码,一眼我就瞧见了这个醒目的hash单词,果断去Location类重写了下hashCode方法:
在这里插入图片描述
运行成功!

重温:Java hashCode() 和 equals()的若干问题解答
引用大佬的理解:
对于不会使用到散列表(HashSet, Hashtable, HashMap)来装载对象的情况,才会使用到hashCode,本文刚好是HashMap,本质就是两个对象按照super.hashCode()生成的结果不同,造成equals比较两个对象不相等,故要重写hashCode使用自己的算法让计算后的值相同。

### **获取重复的 `kks` 值的方法** 你的代码目前只判断 `kks` 是否有重复,但无法知道 **具体哪些值重复**。以下是几种优化方案: --- ### **方法 1:使用 `Collectors.groupingBy` 统计重复值** ```java public List<String> findDuplicateKks(List<Map<String, Object>> listData) { // 按 kks 分组,统计出现次数 Map<String, Long> kksCountMap = listData.stream() .map(map -> (String) map.get("kks")) // 假设 kks 是 String 类型 .filter(Objects::nonNull) .collect(Collectors.groupingBy( kks -> kks, Collectors.counting() )); // 返回出现次数 > 1 的 kks return kksCountMap.entrySet().stream() .filter(entry -> entry.getValue() > 1) .map(Map.Entry::getKey) .collect(Collectors.toList()); } ``` **示例输出**: ```java List<Map<String, Object>> data = List.of( Map.of("kks", "A001"), Map.of("kks", "A002"), Map.of("kks", "A001"), // 重复 Map.of("kks", "A003"), Map.of("kks", "A002") // 重复 ); List<String> duplicates = findDuplicateKks(data); System.out.println(duplicates); // 输出: [A001, A002] ``` --- ### **方法 2:使用 `Set` 记录重复值** ```java public List<String> findDuplicateKks(List<Map<String, Object>> listData) { Set<String> seen = new HashSet<>(); return listData.stream() .map(map -> (String) map.get("kks")) .filter(Objects::nonNull) .filter(kks -> !seen.add(kks)) // 如果 add 返回 false,说明已存在 .distinct() // 避免重复报告同一个 kks 多次 .collect(Collectors.toList()); } ``` **特点**: - 更高效(只需遍历一次)。 - 使用 `Set.add()` 的返回值判断是否重复。 --- ### **方法 3:返回重复值的完整记录(含行号)** 如果还需要知道 **哪些行的数据重复**: ```java public Map<String, List<Integer>> findDuplicateKksWithLineNumbers(List<Map<String, Object>> listData) { Map<String, List<Integer>> kksLineMap = new HashMap<>(); for (int i = 0; i < listData.size(); i++) { String kks = (String) listData.get(i).get("kks"); if (kks != null) { kksLineMap.computeIfAbsent(kks, k -> new ArrayList<>()).add(i + 1); // 行号从1开始 } } // 过滤出重复的 kks return kksLineMap.entrySet().stream() .filter(entry -> entry.getValue().size() > 1) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } ``` **示例输出**: ```java { "A001": [1, 3], // 第1行和第3行重复 "A002": [2, 5] // 第2行和第5行重复 } ``` --- ### **如何选择?** | 场景 | 推荐方法 | |------|---------| | 只需知道重复的 `kks` 值 | **方法 1** 或 **方法 2** | | 需要知道重复值的行号 | **方法 3** | | 数据量极大,需高效去重 | **方法 2**(单次遍历) | --- ### **
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值