迭代并从地图中删除
我在做:
for (Object key : map.keySet()) if (something) map.remove(key);
抛出一个ConcurrentModificationException,所以我改变它:
for (Object key : new ArrayList<Object>(map.keySet())) if (something) map.remove(key);
这个和修改地图的任何其他过程都在同步块中。
有更好的解决scheme吗?
如果没有人提出更好的解决scheme,首先要说没有得到滴答声;)
这是一个代码示例,使用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(); } }
从Java 1.8开始,您可以使用lambdaexpression式和stream来实现这一点:
map.entrySet().removeIf(e-> <boolean expression> );
使用一个真正的迭代器。
Iterator<Object> it = map.keySet().iterator(); while (it.hasNext()) { it.next(); if (something) it.remove(); }
实际上,您可能需要迭代entrySet()
而不是keySet()
来使其工作。
有更好的解决scheme吗?
那么,在一个声明中肯定有一个更好的方法,但这取决于基于哪些元素被删除的条件。
例如:删除所有这些元素的value
testing ,然后使用下面:
map.values().removeAll(Collections.singleton("test"));
更新它可以在Java 8中使用Lambdaexpression式在一行中完成。
map.entrySet().removeIf(e-> <boolean expression> );
我知道这个问题太老了, 但更新更好的方式来做事情没有任何伤害:)
的ConcurrentHashMap
你可以使用java.util.concurrent.ConcurrentHashMap
。
它实现了ConcurrentMap
(它扩展了Map
接口)。
例如 :
Map<Object, Content> map = new ConcurrentHashMap<Object, Content>(); for (Object key : map.keySet()) { if (something) { map.remove(key); } }
这种方法不会影响你的代码。 只有map
types不同。
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)); 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
遍历地图时,必须使用Iterator
来安全地移除元素。
我同意Paul Tomblin。 我通常使用键集的迭代器,然后根据我的条件为该键的值:
Iterator<Integer> it = map.keySet().iterator(); while(it.hasNext()) { Integer key = it.next(); Object val = map.get(key); if (val.shouldBeRemoved()) { it.remove(); } }
也许你可以遍历地图寻找键来删除和存储在一个单独的集合。 然后从地图上删除键的集合。 迭代时修改地图通常是不被接受的。 如果地图非常大,这个想法可能会受到怀疑。
另一种更详细的方式
List<SomeObject> toRemove = new ArrayList<SomeObject>(); for (SomeObject key: map.keySet()) { if (something) { toRemove.add(key); } } for (SomeObject key: toRemove) { map.remove(key); }
这应该也是一样
running is ConcurrentMap<Integer, String> Set<Entry<Integer, String>> set = running.entrySet(); for (Entry<Integer, String> entry : set ) { if (entry.getKey()>600000) { set.remove(entry); } }
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(); } }