跳转到主内容
极星编程网:以代码为星,赴技术山海!

如何优化 Map 遍历:优先使用 entrySet 而非 keySet

遍历 map 时,若需同时访问键与值,应直接使用 `entryset()` 迭代而非 `keyset()` 加 `get()`,避免重复哈希查找,提升性能并消除 sonarqube 的 rspec-2864 代码异味警告。 在 Java 开发中,Map 是高频使用的集合类型。但一个常见却容易被忽视的性能陷阱是: 仅通过 keySet() 遍历,再在循环体内反复调用 map.get(key) 获取对应值 。这种写法看似直观,实则隐含冗余开销——每次 get() 都会重新执行哈希计算、桶定位与键比对(尤其在 HashMap 中),时间复杂度虽为平均 O(1),但常数因子显著增加;在大容量或高频调用场景下,性能损耗可被量化。 更优解是使用 map.entrySet():它返回 Set>,其中每个 Entry 封装了 键值对 的引用, 直接通过 entry.getKey() 和 entry.getValue() 即可零成本获取二者 ,无需额外查找。 以原始代码为例:
// ❌ 低效:keySet + get → 每次循环触发一次哈希查找 for (String accounts : shiftDatesMap.keySet()) { Set shiftDates = shiftDatesMap.get(accounts); // 不必要! // ... 后续逻辑 }
应重构为: Eclipse导入Android或其他的JAVA项目的正确方法 WORD版 本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看 下载
// ✅ 高效:entrySet 一次性获取键值对 for (Map.Entry> entry : shiftDatesMap.entrySet()) { String accounts = entry.getKey(); Set shiftDates = entry.getValue(); // 直接引用,无开销 // ... 后续逻辑复用 accounts 和 shiftDates }
进一步结合您的业务逻辑(如匹配 Groups 并提取日期),完整优化示例如下:
public Set getAccountShiftDate(Map> shiftDatesMap, List shiftSchedule) { Set accountShiftDatesTemplate = new HashSet<>(); for (Map.Entry> entry : shiftDatesMap.entrySet()) { String accounts = entry.getKey(); Set shiftDates = entry.getValue(); Optional shiftOptional = shiftSchedule.stream() .filter(g -> StringUtils.equalsIgnoreCase(accounts, g.getLongName())) .findFirst(); if (shiftOptional.isPresent()) { // 假设此处从 shiftDates 或 Groups 中解析 Date 并添加到结果集 // accountShiftDatesTemplate.addAll(parseDates(shiftDates)); } } return accountShiftDatesTemplate; }
⚠️ 注意事项: 此优化 仅在循环内需访问值(或键+值)时生效 ;若仅需键(如做存在性校验),keySet() 仍合理; entrySet() 返回的是 Map 内部结构的视图,修改 Entry 的值(如 entry.setValue(...))可能影响原 Map(取决于具体实现,HashMap 支持); 使用增强 for 循环时,确保 Map 非 null;若可能为空,建议提前判空或使用 Objects.requireNonNull(); SonarQube 规则 RSPEC-2864 的本质是鼓励“一次定位,多次利用”,这既是性能实践,也是 代码可读性 与意图清晰性的体现。 总结:将 keySet() 迭代升级为 entrySet(),是 Java Map 遍历的黄金准则之一——它用一行代码的微小改动,换来确定性的性能收益与静态分析合规性,值得在所有审查清单中置顶。

相关文章