paint-brush
更改密钥,丢失值经过@mcsee
544 讀數
544 讀數

更改密钥,丢失值

经过 Maximiliano Contieri4m2025/02/24
Read on Terminal Reader

太長; 讀書

当您使用可变对象作为散列集合中的键时,更改它们会破坏契约。
featured image - 更改密钥,丢失值
Maximiliano Contieri HackerNoon profile picture
0-item


更改密钥,丢失值


TL;DR:当您使用可变对象作为散列集合中的键时,更改它们会破坏契约。

问题😔

  • 失去的价值观
  • 硬调试
  • 违反最小意外原则
  • 意外行为

解决方案😃

  1. 使用不可变对象作为键。
  2. 很好地覆盖equals/hashCode
  3. 使用 final 字段(如果你的语言允许的话)
  4. 变异后重新哈希(这是一个过度设计的解决方案)

上下文

当您使用可变对象作为散列集合中的键时,在添加相关对象之后更改它们的键可能会使其无法检索。


发生这种情况的原因是哈希码发生了变化,并且集合无法在正确的存储桶中找到对象。

示例代码📖

错误❌

 class MutableKey { int id; MutableKey(int newId) { this.id = newId; } @Override public int hashCode() { return this.id; } @Override public boolean equals(Object objectToCompare) { if (this == objectToCompare) return true; MutableKey that = (MutableKey) objectToCompare; return id == that.id; } } MutableKey key = new MutableKey(42); Map<MutableKey, String> map = new HashMap<>(); map.put(key, "Yes Album"); // The key mutates key.id = 90125; // Now you cannont retrieve the album System.out.println(map.get(key)); // Output: null

对的👉

 class ImmutableKey { private final int id; ImmutableKey(int newId) { this.id = newId; } @Override public int hashCode() { return this.id; } @Override public boolean equals(Object objectToCompare) { if (this == objectToCompare) return true; ImmutableKey that = (ImmutableKey) objectToCompare; return id == that.id; } } ImmutableKey key = new ImmutableKey(42); Map<ImmutableKey, String> map = new HashMap<>(); map.put(key, "Yes Album"); System.out.println(map.get(key)); // Output: Yes Album

检测🔍

  • 半自动


您可以通过检查是否使用可变对象作为基于哈希的集合中的键来检测这种气味。


诸如 linters 或 IDE 检查之类的自动化工具也可以标记可变键。

标签🏷️

  • 可变性

等级🔋

  • 中间的

双射为何如此重要

现实世界和程序之间的双射很重要,因为它可以确保对象准确反映它们应该表示的关系。


在现实世界中,密钥通常是不可变的(例如,ID,名称)。


当您将这些键建模为可变对象时,您会打破现实世界与MAPPER中的程序之间的一一对应关系。


当使用可变键破坏这种双射时,会导致映射不一致,从而导致检索失败和意外行为。

人工智能生成

如果人工智能生成器生成可变对象作为键而不考虑其含义,则可能产生这种气味。


由于人工智能生成器受到原始痴迷的影响,因此这种情况很少发生。

人工智能检测

人工智能生成器可以通过指令分析基于哈希的集合中可变对象的使用情况并标记潜在问题来检测这种气味。


您可以指示 AI 寻找没有最终字段或在创建后修改对象状态的方法的类。

尝试一下!🛠

记住:人工智能助手会犯很多错误

没有正确指导

有具体说明

ChatGPT

ChatGPT

克劳德

克劳德

困惑

困惑

副驾驶

副驾驶

双子座

双子座

DeepSeek

DeepSeek

元人工智能

元人工智能

结论

当您使用可变对象作为键时,您可能会面临破坏键的状态和哈希码之间的契约的风险。


使用不可变对象来避免此问题。

关系👩‍❤️‍💋‍👨

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxxiv

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxv

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxiv

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxxvi

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xviii

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxvi

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xlii

更多信息📕

免责声明📘

认为“代码异味”是“代码异味”。

致谢🙏

凯瑟琳·特里普 (Kathryn Tripp)Unsplash上拍摄的照片


程序最重要的属性是它是否能实现用户的意图。


卡尔·霍尔



本文是 CodeSmell 系列的一部分。