连续循环遍历 HashMap 需要什么代码?

发布于 2024-12-09 12:08:48 字数 1001 浏览 1 评论 0原文

目前,我的代码导致间歇性的 ConcurrentModificationException 错误,可能是因为我循环遍历 HashMap 的方式:

for (Map.Entry<String, Entity> entry : entities.entrySet()) {
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        entities.remove(key);
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);
}
// updateInfo call
ViewManager.getInstance().updateInfo(summary());
}

How does one Continuous loop through a HashMap and避免 ConcurrentModificationException 错误?

Currently my code is causing intermittent ConcurrentModificationException errors, probably because of the way I am looping through the HashMap:

for (Map.Entry<String, Entity> entry : entities.entrySet()) {
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        entities.remove(key);
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);
}
// updateInfo call
ViewManager.getInstance().updateInfo(summary());
}

How does one continuously loop though a HashMap and avoid a ConcurrentModificationException error?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

绻影浮沉 2024-12-16 12:08:48

循环遍历地图时无法修改地图。您必须复制地图,使用 ConcurrentHashMap,或使用 迭代器< /a>.如果是在多线程环境下,那么可以在synchronized块中进行修改。

另一种选择是使用迭代器

我用下面的迭代器重写了 for for 循环:

for(Iterator<Map.Entry<String, Entity>> iterator = entities.entrySet().iterator(); iterator.hasNext(); ){
    Map.Entry<String, Entity> entry = iterator.next();
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        //Notice using an iterator to remove 
        iterator.remove();
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);

}

我不确定连续循环 HashMap 的部分。哈希映射具有有限的键集,因此通常可以循环遍历键集。如果您出于某种原因想要连续循环,那么您需要首先告诉我们其背后的原因以及该连续循环的终止条件(它不可能是永远,不是吗?)。

You cannot modify a map while looping through it. You either have to make a copy of the map, use a ConcurrentHashMap, or use an iterator. If it is in a multi threaded environment, then you can do the modification in a synchronized block.

Another option is to use an iterator.

I rewrote your for for loop with an iterator below:

for(Iterator<Map.Entry<String, Entity>> iterator = entities.entrySet().iterator(); iterator.hasNext(); ){
    Map.Entry<String, Entity> entry = iterator.next();
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        //Notice using an iterator to remove 
        iterator.remove();
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);

}

I am not sure about the part of continuously looping a HashMap. A hash map has a finite set of keys, so you loop through the key set generally. If you for some reason want to loop continuously then you need to first tell us the reason behind it and also the terminal condition of that continuous loop (it cant really be forever, can it?).

我们的影子 2024-12-16 12:08:48

正如其他答案中所述,使用基于迭代器的 for 循环而不是 for-each 循环是避免 ConcurrentModificationExemptions 的最佳选择。至于无限循环,请查看循环方法。它接受一个 Iterable(例如 HashMap)并返回一个 Iterator,该迭代器不断循环数据,直到 Iterable 为空或中断循环。

As documented in the other answers, using a Iterator based for-loop, instead of a for-each loop, is your best bet for avoiding ConcurrentModificationExemptions. As for the infinite looping, have a look at the cycle method in Guava's Iterators static utility class. It takes an Iterable (such as a HashMap) and returns an Iterator that continuously loops over the data until either the Iterable is empty or you break the loop.

盗琴音 2024-12-16 12:08:48

使用迭代器和 while 循环怎么样?

Iterator<String> iterator = map.iterator();
String key;
String value;
while (iterator.hasNext()) {
 key = iterator.next();
 value = map.get(key);
}

how about using an iterator and while loop?

Iterator<String> iterator = map.iterator();
String key;
String value;
while (iterator.hasNext()) {
 key = iterator.next();
 value = map.get(key);
}
双手揣兜 2024-12-16 12:08:48

您不能在循环时调用 Remote(key) 方法,但可以通过迭代器删除条目:

Map<String, String> map = new HashMap<String, String>();
map.put("one", "1");
map.put("two", "2");
map.put("three", "3");

for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext();)
{
    Map.Entry<String, String> curEntry = i.next();
    if (curEntry.getKey().equals("two"))
        i.remove();
}

You cannot call remote(key) method while looping, but you can remove entries via an iterator:

Map<String, String> map = new HashMap<String, String>();
map.put("one", "1");
map.put("two", "2");
map.put("three", "3");

for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext();)
{
    Map.Entry<String, String> curEntry = i.next();
    if (curEntry.getKey().equals("two"))
        i.remove();
}
夏末 2024-12-16 12:08:48

假设您仅在线程中访问映射,请使用迭代器,正如其他人建议的那样。

我在考虑迭代哈希图时的性能,
所以我对 10^6 随机 Long 进行了 25 次迭代的快速测试,并删除了其中的 10%,
使用不同的映射实现:ConcurrentHashMap、HashMap、LinkedHashMap
和一个树状图。

链接的哈希图据说是为迭代而定制的,而且它似乎是最有效的。我认为峰值是由于 gc 造成的。

...但差异比我预期的要小。

在此处输入图像描述

Assuming that you are accessing the map in only on thread, use an iterator, as the other guys suggest.

I was thinking about the performance when iterating over a hashmap,
so i did a quick test of 25 iterations over 10^6 random Longs and removing 10% of then,
using different map implementations: ConcurrentHashMap, HashMap, LinkedHashMap
and a TreeMap.

The linked hashmap is supposedly tailored for iterating, and it seems to be the most efficient. I suppose the spikes are due to gc.

...but the differences are smaller than I had anticipated.

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文