我正在做:
for (Object key : map.keySet()) if (something) map.remove(key);
它抛出了一个ConcurrentModificationException,所以我把它改为:
for (Object key : new ArrayList<Object>(map.keySet())) if (something) map.remove(key);
这个过程以及修改映射的任何其他过程都在同步块中。
有没有更好的解决方案?
使用真正的迭代器。
Iterator<Object> it = map.keySet().iterator(); while (it.hasNext()) { it.next(); if (something) it.remove(); }
实际上,你可能需要遍历entrySet()而不是keySet()才能使其工作。
entrySet()
keySet()
在遍历映射时,必须使用Iterator来安全地删除元素。
Iterator
下面是一个在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(); } }
也许您可以遍历映射,寻找要删除的键,并将它们存储在单独的集合中。然后从映射中删除键集合。在迭代过程中修改地图通常是不受欢迎的。如果地图非常大,这个想法可能是可疑的。
另一种更详细的方法
List<SomeObject> toRemove = new ArrayList<SomeObject>(); for (SomeObject key: map.keySet()) { if (something) { toRemove.add(key); } } for (SomeObject key: toRemove) { map.remove(key); }
我同意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(); } }
当然,在条语句中肯定有更好的方法来这样做,但这取决于基于哪些元素被删除的条件。
例如:删除所有value为测验的元素,然后使用如下语句:
value
map.values().removeAll(Collections.singleton("test"));
<强>更新 它可以在Java 8中使用Lambda表达式在单行中完成
map.entrySet().removeIf(e-> <boolean expression> );
我知道这个问题太老了,但更新更好的做事方式并没有什么坏处:)
这也应该可以工作。
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.getKey()); } }
ConcurrentHashMap
你可以使用java.util.concurrent.ConcurrentHashMap。
java.util.concurrent.ConcurrentHashMap
它实现了ConcurrentMap(扩展了Map接口)。
ConcurrentMap
Map
如。:
Map<Object, Content> map = new ConcurrentHashMap<Object, Content>(); for (Object key : map.keySet()) { if (something) { map.remove(key); } }
这种方法不会影响代码。只有map类型不同。
map
从Java 8开始,你可以这样做:
map.entrySet().removeIf(e -> <boolean expression>);
Oracle Docs: entrySet()
集合是由映射支持的,所以对映射的更改会反映在集合中,反之亦然
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(); } }
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