我在做:
for (Object key : map.keySet())
if (something)
map.remove(key);
引发了ConcurrentModificationException,因此我将其更改为:
for (Object key : new ArrayList<Object>(map.keySet()))
if (something)
map.remove(key);
这个,以及修改地图的任何其他过程都在同步块中。
有更好的解决方案吗?
如果没有人提出更好的解决方案,首先要说不得嘀嗒;)
答案 0 :(得分:364)
以下是在for循环中使用迭代器删除条目的代码示例。
Map<String, String> map = new HashMap<String, String>() {
{
put("test", "test123");
put("test2", "test456");
}
};
for(Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, String> entry = it.next();
if(entry.getKey().equals("test")) {
it.remove();
}
}
答案 1 :(得分:210)
从Java 8开始,您可以按照以下方式执行此操作:
map.entrySet().removeIf(e -> <boolean expression>);
答案 2 :(得分:95)
使用真正的迭代器。
Iterator<Object> it = map.keySet().iterator();
while (it.hasNext())
{
it.next();
if (something)
it.remove();
}
实际上,您可能需要迭代entrySet()
而不是keySet()
才能使其发挥作用。
答案 3 :(得分:43)
有更好的解决方案吗?
嗯,肯定有一种更好的方式在单一陈述中这样做,但这取决于基于哪些元素被移除的条件。
例如:删除所有value
test 的元素,然后使用以下内容:
map.values().removeAll(Collections.singleton("test"));
<强>更新强> 它可以使用Java 8中的Lambda表达式在一行中完成。
map.entrySet().removeIf(e-> <boolean expression> );
我知道这个问题已经过时了,但是更新更好的做事方式没有任何损害:)
答案 4 :(得分:22)
<强>的ConcurrentHashMap 强>
您可以使用java.util.concurrent.ConcurrentHashMap
。
它实现了ConcurrentMap
(扩展了Map
接口)。
<强> E.g 强>:
Map<Object, Content> map = new ConcurrentHashMap<Object, Content>();
for (Object key : map.keySet()) {
if (something) {
map.remove(key);
}
}
这种方法使您的代码不受影响。只有map
类型不同。
答案 5 :(得分:7)
Java 8支持更具声明性的迭代方法,因为我们指定了我们想要的结果而不是如何计算它。新方法的好处是它可以更易读,更不容易出错。
public static void mapRemove() {
Map<Integer, String> map = new HashMap<Integer, String>() {
{
put(1, "one");
put(2, "two");
put(3, "three");
}
};
map.forEach( (key, value) -> {
System.out.println( "Key: " + key + "\t" + " Value: " + value );
});
map.keySet().removeIf(e->(e>2)); // <-- remove here
System.out.println("After removing element");
map.forEach( (key, value) -> {
System.out.println( "Key: " + key + "\t" + " Value: " + value );
});
}
结果如下:
Key: 1 Value: one
Key: 2 Value: two
Key: 3 Value: three
After removing element
Key: 1 Value: one
Key: 2 Value: two
答案 6 :(得分:5)
在遍历地图时,您必须使用Iterator
安全地删除元素。
答案 7 :(得分:3)
我同意保罗·汤姆林的观点。我通常使用键集的迭代器,然后将我的条件基于该键的值:
Iterator<Integer> it = map.keySet().iterator();
while(it.hasNext()) {
Integer key = it.next();
Object val = map.get(key);
if (val.shouldBeRemoved()) {
it.remove();
}
}
答案 8 :(得分:2)
另一种更详细的方式
List<SomeObject> toRemove = new ArrayList<SomeObject>();
for (SomeObject key: map.keySet()) {
if (something) {
toRemove.add(key);
}
}
for (SomeObject key: toRemove) {
map.remove(key);
}
答案 9 :(得分:1)
也许您可以遍历地图,查找要删除的密钥并将其存储在单独的集合中。然后从地图中删除键集合。迭代时修改地图通常是不受欢迎的。如果地图非常大,这个想法可能会被怀疑。
答案 10 :(得分:1)
这也应该有用..
ConcurrentMap<Integer, String> running = ... create and populate map
Set<Entry<Integer, String>> set = running.entrySet();
for (Entry<Integer, String> entry : set)
{
if (entry.getKey()>600000)
{
set.remove(entry);
}
}
答案 11 :(得分:-1)
Set s=map.entrySet();
Iterator iter = s.iterator();
while (iter.hasNext()) {
Map.Entry entry =(Map.Entry)iter.next();
if("value you need to remove".equals(entry.getKey())) {
map.remove();
}
}