Какие базовые операции на карте разрешены во время итерации по ней?

Скажем, я повторяю карту в Java ... Я не понимаю, что я могу сделать с этой картой в процессе итерации по ней. Думаю, меня больше всего смущает это предупреждение в Javadoc для метода удаления интерфейса Iterator:

[...] Поведение итератора не определено, если базовая коллекция изменяется во время выполнения итерации любым способом, кроме вызова этого метода.

Я точно знаю, что могу вызвать метод удаления без каких-либо проблем. Но, перебирая коллекцию карт, могу ли я:

  1. Измените значение, связанное с ключом, с помощью метода put класса Map (поместите с существующим ключом)?

  2. Добавить новую запись с помощью метода put класса Map (поставить с новым ключом)?

  3. Удалить запись с помощью метода удаления класса Map?

Я предполагаю, что я могу безопасно сделать №1 (поставить на существующий ключ), но небезопасно сделать №2 или №3.

Заранее благодарим за любые разъяснения по этому поводу.


person Chris Markle    schedule 29.01.2009    source источник


Ответы (4)


Вы можете использовать Iterator.remove(), а при использовании итератора entrySet (Map.Entry's) вы можете использовать Map.Entry.setValue(). Все остальное, и все ставки отключены - вы не должны изменять карту напрямую, а некоторые карты не разрешают один или оба вышеупомянутых метода.

В частности, ваши (1), (2) и (3) запрещены.

Вы можете обойтись установкой существующего значения ключа с помощью объекта Map, но документация Set.iterator() специально исключает это, и это будет зависеть от конкретной реализации:

Если карта изменяется во время итерации по набору (за исключением собственной операции удаления итератора или операции setValue для записи карты, возвращаемой итератором), результаты итерации не определены . (курсив мой)

person Lawrence Dol    schedule 29.01.2009
comment
Подтверждаю, что ваши предложения хороши. Map.Entry.setValue () работает как шарм, Iterator.remove () тоже. - person gouessej; 04.05.2012
comment
Для полноты, как насчет изменения текущего значения итератора через общедоступный мутатор? Невозможно, чтобы карта отображала все вызовы методов записи, верно? - person Patrick M; 08.10.2015

Если вы посмотрите на класс HashMap, вы увидите поле под названием «modCount». Вот как карта узнает, когда она была изменена во время итерации. Любой метод, увеличивающий modCount при повторении, вызовет исключение ConcurrentModificationException.

Тем не менее, вы МОЖЕТЕ поместить значение в карту, если ключ уже существует, эффективно обновляя запись новым значением:

 Map<String, Object> test = new HashMap<String, Object>();
 test.put("test", 1);

 for(String key : test.keySet())
 {
     test.put(key, 2); // this works!
 }

 System.out.println(test); // will print "test->2"

Когда вы спрашиваете, можете ли вы выполнять эти операции «безопасно», вам не нужно слишком беспокоиться, потому что HashMap спроектирован так, чтобы генерировать это ConcurrentModificationException, как только он сталкивается с такой проблемой. Эти операции быстро завершатся неудачей; они не оставят карту в плохом состоянии.

person Outlaw Programmer    schedule 29.01.2009
comment
Эти методы пытаются работать быстро, но из-за проблем с параллелизмом памяти они могут не всегда, если модификация выполняется в другом потоке. Всегда следуйте документации API; никогда не нарушайте его, потому что я пробовал это, и он работал, поскольку он может работать только на вашей (а) JVM, или (б) оборудовании, или (в) определенной конфигурации, но не на других. - person Lawrence Dol; 10.01.2014

Глобального ответа нет. Интерфейс карты предоставляет выбор пользователям. К сожалению, я думаю, что все реализации в jdk используют реализацию fail-fast (вот определение fail-fast, как указано в HashMap Javadoc):

Итераторы, возвращаемые всеми «методами представления коллекции» этого класса, работают без сбоев: если карта структурно изменена в любое время после создания итератора, любым способом, кроме собственного метода удаления итератора, итератор выдаст исключение ConcurrentModificationException . Таким образом, перед лицом одновременной модификации итератор быстро и чисто выходит из строя, вместо того, чтобы рисковать произвольным, недетерминированным поведением в неопределенное время в будущем.

person Nicolas    schedule 29.01.2009

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

person Sasha    schedule 29.01.2009