Итерация и удаление с карты

Я делал:

for (Object key : map.keySet())
    if (something)
        map.remove(key);

который бросил исключение ConcurrentModificationException, поэтому я изменил его на:

for (Object key : new ArrayList<Object>(map.keySet()))
    if (something)
        map.remove(key);

и любые другие процедуры, которые изменяют карту, находятся в синхронизированных блоках.

есть ли лучшее решение?

если никто не придумает лучшего решения, сначала скажем, что не получает галочку;)

Ответ 1

Начиная с Java 8 вы можете сделать это следующим образом:

map.entrySet().removeIf(e -> <boolean expression>);

Ответ 2

Вот пример кода для использования итератора в цикле 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();
    }
}

Ответ 3

Используйте настоящий итератор.

Iterator<Object> it = map.keySet().iterator();

while (it.hasNext())
{
  it.next();
  if (something)
    it.remove();
 }

На самом деле вам может потребоваться выполнить итерацию по entrySet() вместо keySet(), чтобы эта работа работала.

Ответ 4

есть ли лучшее решение?

Ну, есть, конечно, лучше способ сделать это в одиночном утверждении, но это зависит от условия, на основе которого удаляются элементы. p >

Например: удалить все те элементы, где value является тестом, а затем использовать ниже:

map.values().removeAll(Collections.singleton("test"));

UPDATE Это можно сделать в одной строке, используя выражение Lambda в Java 8.

map.entrySet().removeIf(e-> <boolean expression> );

Я знаю, что этот вопрос слишком стар, но нет никакого вреда в обновлении лучшего способа делать вещи:)

Ответ 5

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 отличается.

Ответ 6

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

Ответ 7

Вы должны использовать Iterator для безопасного удаления элемента при перемещении карты.

Ответ 8

Я согласен с Полом Томблином. Я обычно использую итератор набора ключей, а затем основываю свое условие на значении для этого ключа:

Iterator<Integer> it = map.keySet().iterator();
while(it.hasNext()) {
    Integer key = it.next();
    Object val = map.get(key);
    if (val.shouldBeRemoved()) {
        it.remove();
    }
}

Ответ 9

Альтернативный, более подробный способ

List<SomeObject> toRemove = new ArrayList<SomeObject>();
for (SomeObject key: map.keySet()) {
    if (something) {
        toRemove.add(key);
    }
}

for (SomeObject key: toRemove) {
    map.remove(key);
}

Ответ 10

Возможно, вы можете выполнить итерацию по карте, ища ключи для удаления и сохранения их в отдельной коллекции. Затем удалите коллекцию ключей с карты. Изменение карты в то время как итерация обычно неодобрительно. Эта идея может быть подозрительной, если карта очень велика.

Ответ 11

И это должно работать так же..

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());    
  }
}

Ответ 12

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();
    }
}