Hashmap.keySet (), foreach и удалить - PullRequest
14 голосов
/ 08 января 2010

Я знаю, что это обычно большое нет-нет, чтобы удалить из списка, используя java-метод "foreach", и что нужно использовать iterator.remove (). Но безопасно ли удалить (), если я зацикливаюсь на keySet () HashMap? Как это:

for(String key : map.keySet()) {
  Node n = map.get(key).optimize();
  if(n == null) {
   map.remove(key);
  } else {
   map.put(key, n);
  }
}

Ответы [ 2 ]

18 голосов
/ 08 января 2010

EDIT:

Я не заметил, что вы на самом деле не добавляли на карту - вы просто меняли значение в записи. В этом случае решение pstanton (перед редактированием 1 ) имеет значение почти , но вы должны вызывать setValue для записи, возвращаемой итератором, вместо вызова map.put. (Возможно возможно , что map.put будет работать, но я не верю, что это гарантировано - тогда как документы утверждают, что entry.setValue будет работать.)

for (Iterator<Map.Entry<String, Node>> it = map.entrySet().iterator(); 
     it.hasNext();)
{
    Map.Entry<String, Node> entry = it.next();
    Node n = entry.getValue().optimize();
    if(n == null) 
    {
        it.remove();
    }
    else
    {
        entry.setValue(n);
    }
}

(Жаль, что entry не имеет метода remove, в противном случае вы все равно можете использовать расширенный синтаксис для цикла for, делая его несколько менее громоздким.)

Старый ответ

(я оставил это здесь для более общего случая, когда вы просто хотите сделать произвольные модификации.)

Нет - вы не должны ни добавлять на карту, ни удалять из нее напрямую. Набор, возвращаемый HashSet.keySet(), представляет собой вид клавиш, а не снимок.

Вы можете удалить через итератор, хотя для этого требуется, чтобы вы использовали итератор явно, а не через расширенный цикл for.

Один простой вариант - создать новый набор из оригинала:

for (String key : new HashSet<String>(map.keySet())) {
    ...
}

На данный момент вы в порядке, потому что вы не вносите никаких изменений в набор.

РЕДАКТИРОВАТЬ: Да, вы определенно можете удалить элементы с помощью итератора набора ключей. Из документов на HashMap.keySet():

Набор поддерживает удаление элементов, который удаляет соответствующие отображение с карты, через Iterator.remove, Set.remove, удалить все, сохранить все и очистить операции. Это не поддерживает операции добавления или добавления всех.

Это указывается даже в самом интерфейсе Map.


1 Я решил отредактировать свой ответ, а не просто комментировать ответы Псантона, так как я полагал, что дополнительная информация, которую я получил для подобных, но различных ситуаций, была достаточно полезна, чтобы заслужить этот ответ.

12 голосов
/ 08 января 2010

вы должны использовать набор записей:

for(Iterator<Map.Entry<String, Node>> it = map.entrySet().iterator(); it.hasNext();)
{
      Map.Entry<String, Node> entry = it.next();
      Node n = entry.getValue().optimize();
      if(n == null) 
          it.remove();
      else
          entry.setValue(n);
}

РЕДАКТИРОВАТЬ фиксированный код

...