Ответ 1
Начиная с Java 8 вы можете сделать это следующим образом:
map.entrySet().removeIf(e -> <boolean expression>);
Я делал:
for (Object key : map.keySet())
if (something)
map.remove(key);
который бросил исключение ConcurrentModificationException, поэтому я изменил его на:
for (Object key : new ArrayList<Object>(map.keySet()))
if (something)
map.remove(key);
и любые другие процедуры, которые изменяют карту, находятся в синхронизированных блоках.
есть ли лучшее решение?
если никто не придумает лучшего решения, сначала скажем, что не получает галочку;)
Начиная с Java 8 вы можете сделать это следующим образом:
map.entrySet().removeIf(e -> <boolean expression>);
Вот пример кода для использования итератора в цикле 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();
}
}
Используйте настоящий итератор.
Iterator<Object> it = map.keySet().iterator();
while (it.hasNext())
{
it.next();
if (something)
it.remove();
}
На самом деле вам может потребоваться выполнить итерацию по entrySet()
вместо keySet()
, чтобы эта работа работала.
есть ли лучшее решение?
Ну, есть, конечно, лучше способ сделать это в одиночном утверждении, но это зависит от условия, на основе которого удаляются элементы. p >
Например: удалить все те элементы, где value
является тестом, а затем использовать ниже:
map.values().removeAll(Collections.singleton("test"));
UPDATE Это можно сделать в одной строке, используя выражение Lambda в Java 8.
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
отличается.
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
Вы должны использовать Iterator
для безопасного удаления элемента при перемещении карты.
Я согласен с Полом Томблином. Я обычно использую итератор набора ключей, а затем основываю свое условие на значении для этого ключа:
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);
}
Возможно, вы можете выполнить итерацию по карте, ища ключи для удаления и сохранения их в отдельной коллекции. Затем удалите коллекцию ключей с карты. Изменение карты в то время как итерация обычно неодобрительно. Эта идея может быть подозрительной, если карта очень велика.
И это должно работать так же..
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());
}
}
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();
}
}