【问题标题】:Setting Hashmap in a loop循环设置Hashmap
【发布时间】:2010-03-03 02:59:12
【问题描述】:

我有以下代码:

Map<String, ObjectType> objectMap = new HashMap<String, ObjectType>();
for (ObjectType obj : objects) {
    obj.setSomeProperty("property value");
    objectMap.put(obj.getADiffProperty(), obj);
}

似乎在循环迭代期间,某些 obj 属性针对不同的键更改,而不是当前设置的键。上面的代码有问题吗?不知何故,对 obj 的引用被 for 循环回收了?

这个循环也在外循环中。

更新
我在下面提供完整的方法。我观察到上述行为的实际位置是在 Singleton 类中定义为 Map&lt;String, Map&lt;String, GlossaryTerm&gt;&gt; loadedTerms = new HashMap&lt;String, Map&lt;String, GlossaryTerm&gt;&gt;(); 的外部映射中。

List<Audience> audiences = ContentAccess.getAudienceList();

List<GlossaryTerm> glossaryTerms = ContentAccess.getAllReplacementCIs();                            

for (Audience audience : audiences) {                   
    Map<String, GlossaryTerm> termMap = new HashMap<String, GlossaryTerm>();
    for (GlossaryTerm term : glossaryTerms) {
       String definition = term.getProductGlossary().get(audience.getName());
       if (definition != null)
           term.setDefinition(definition);
       termMap.put(term.getPhrase(), term);
   }                        
   loadedTerms.put(audience.getChannelId(), termMap);
}

【问题讨论】:

  • 外循环是做什么的?它会影响 sn-p 中的任何变量吗?
  • 我们可以假设 setDefinition() 是一个没有副作用的简单设置器吗? getPhrase() 也一样?
  • 是设置字符串的简单设置器。 getPhrase() 也一样。
  • 如果可以,最好让 getAudienceList()、getAllReplacementCIs() 等返回空列表,从不为空。空检查会损害您的代码。另外, size() > 0 测试 (a) 可以替换为 isEmpty();和 (b) 可以被删除,因为 for 循环将为空列表迭代零次。
  • 感谢您的建议。我实现了这些,返回了空列表。

标签: java iteration hashmap


【解决方案1】:

我不认为你认为正在发生的事情正在发生。对于每次迭代,对象引用都是应该的。我认为必须发生其他事情 - 其他地方的属性正在发生变化,或者没有您认为它们最初具有的值。放入一些 printlns 来追踪到底发生了什么。您显示的代码不能更改错误的属性。

【讨论】:

  • 我正在运行调试并观察HashMap(最外面的那个),并且我专门寻找的条目被正确放入,并且在循环的进行过程中它改变了我!很奇怪!
  • 您能否在发生变化的字段上放置一个观察点,然后查看它何时发生变化?或者:您是否可以覆盖该条目 - 多个术语是否具有相同的短语?还是具有相同哈希码的短语?
  • 键是字符串。两个字符串可以具有相同的哈希码吗?这也许是问题所在。我正在调试,会告诉你。这些字符串基本上都是 40 个字符长度的 GUID。
  • 如果您提供 Audience、GlossaryTerms 和 ContentAccess 的代码可能会有所帮助
  • 所以,我用以下方式修改了代码:我实例化了一个新的GlossaryTerm对象,而不是termMap.put(term.getPhrase(), term);,并复制了term中的值,然后将这个新实例放入@987654325 @。现在它工作正常。似乎在 Map 中使用 for each 循环中的变量并不安全。为什么???
【解决方案2】:

似乎在循环迭代期间,某些 obj 属性针对不同的键更改,而不是当前设置的键。上面的代码有问题吗?不知何故,对 obj 的引用被 for 循环回收了?

每次循环时,objectsobj 变量将设置为迭代器的“下一个”元素。如果您在obj 中多次看到相同的参考值,那只能是因为:

  • 引用值在集合、数组或objects 给出的任何内容中确实出现了不止一次,或者

  • setSomePropertygetADiffProperty 中的某些内容或您在循环中执行的其他内容正在更新 objects 作为副作用,或者

  • objects 对象有一个错误的迭代器实现。

另一种可能性是您看到的是具有相同adiff 值的不同对象。

再说什么,我需要看到比您提供的简化 sn-p 更多的源代码。

EDIT - 您提供的额外代码并未发现问题。 (我认为我们可以驳斥任何涉及在迭代列表时更新列表的理论,或者来自 setter 的奇怪副作用。)

我怀疑单例提供的列表之一包含重复项或其他意外。这可能是导致您的问题的原因。

按照@Carl 的建议执行操作,并使用跟踪打印和/或调试器来确定 Collection 单例中的内容以及您的代码实际在做什么。

编辑 2 - 集合是单例类这一事实可能无关紧要。并且 HashMap 的内容不会随机或自发地改变。 (而且您的代码中没有任何绿色小恶魔会合谋使其失败。相信我!)

您似乎具有猜测问题所在并根据这些猜测进行更改的思维方式,希望他们能够解决问题。 停止猜测!这是错误的做法,而且可能只会让事情变得更糟。您需要做的是仔细而有条不紊地调试代码,收集关于您的程序实际在做什么的确凿证据,并仔细解释这些证据......不要诉诸疯狂的想法,即某些事情正在随机改变事物。

编辑 3 - 如果我遇到您的情况,我会请团队中另一位经验丰富的 Java 程序员坐下来帮我调试代码。我仍然偶尔需要自己做这件事,而且我有 10 年以上的 Java 经验和 30 多年的编程经验。有时你在某个问题上遇到了心理障碍,而新思路/新方法就是答案。

向你的团队/老板承认你超出了你的能力范围并需要帮助并不是一件可耻的事情。

【讨论】:

  • 我更新了上面的完整方法。也许是导致问题的单例,尽管在我的测试中我正在运行一个线程并且单例被实现为静态实例化变量,例如private static SingletonClass instance = new SingletonClass();
  • 至于您的怀疑,我将列表从 Singleton 移至本地。甚至尝试摆脱 Singleton。没有不同。地图似乎随机变化!
  • 至于猜测,请参阅我对 Carl 的评论,了解我是如何解决这个问题的,当然还有人尖叫着让我立即提供修复程序!!!我怀疑 Java 运行时中存在错误。我将尝试另一个 JDK。
  • @Eqbal - Java 运行时中的错误不太可能。这是“小绿魔侵扰我的代码”的想法。
  • 感谢您的建议。我在尝试。虽然我有工作的事实意味着我可能不得不继续前进!我不想离开这里而不弄清楚这里发生了什么。
【解决方案3】:

我正在开始一个新的答案,因为 - 嗯,这是一个新的想法,讨论线程变得相当长。

你还没有(我认为)说变化发生的时间。但是您(可能)将相同的术语放入多个地图中,针对不同的受众。与循环变量无关 - 只是您对每个受众重复使用相同的术语列表。但是,当您将术语放入地图时,您也会更改其定义。但是对于每个受众来说,定义(可能)是不同的。所以,具体的例子:

术语 A 对受众 X 定义为“x”,对受众 Y 定义为“y”。您拥有这两个受众。最初,我们遇到观众 X,所以 A 得到定义“x”。 A 被添加到该受众的地图中。现在我们迭代到下一个受众,并将 A 的定义更改为“y”。这会在您引用它的任何地方更改 A - 包括在观众 X 的地图中。这可以解释为什么制作副本可以消除问题。这是你正在经历的吗?

【讨论】:

  • 你在这里一针见血!这正是我所看到的!!!非常感谢!
【解决方案4】:

这可能只是一个拼写错误。您的 sn-p 中没有声明 object,但您的 put 调用使用 object.getADiffProperty() 而不是 obj.getADiffProperty()。这是故意的吗?

【讨论】:

  • 是的,这是一个错字,已更正。感谢您指出。
  • 在这里我想我解决了你的问题。我再看看。
【解决方案5】:

从哪里调用代码?可能有并发问题吗?是否有其他线程(它是 web 应用程序?)访问 ContentAccess?我希望GlossaryTerm 是一个简单的 Dto,对吧?

【讨论】:

  • 好吧,我正在从 Eclipse 中的单个线程进行测试。最终它会/将被从 webapp/servlet 内部调用。是的,GlossaryTerm 是一个简单的 DTO。
猜你喜欢
  • 2020-07-10
  • 2018-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-31
  • 2018-10-15
  • 2013-11-19
  • 1970-01-01
相关资源
最近更新 更多