Метод TreeMap и setValue

В java.util.TreeMap javadoc есть следующее утверждение:

Все пары Map.Entry, возвращаемые методами этого класса, и его представления представляют моментальные снимки отображений в момент их создания. Они не поддерживают метод Entry.setValue. (Обратите внимание, однако, что можно изменить отображения на связанной карте с помощью put.)

Я не получаю эту строку. Каким образом они не поддерживают метод setValue? Когда я использую entrySet() и перебираю объект Map.Entry, он устанавливает значение fine.

    Map<String, Integer> map = new TreeMap<>();
    map.put("dbc", 1);
    map.put("abc", 1);
    map.put("cbc", 1);
    for(Map.Entry<String, Integer> item: map.entrySet()) {
        item.setValue(1);
    }

Ответ 1

Это известная проблема.

  • Существует запись Tracker OpenJDK (JDK-8038146), которая отмечает, что это javadoc. Но есть нечто большее, чем это.

  • Также есть запись базы данных Java Bug (идентификатор ошибки 7006877), которая объясняет, что javadoc был изменен, чтобы сказать, что в Java 6, и что это действительно правда для альтернативной версии TreeMap, которую вы получаете (получаете), если вы запускаете JVM с включенными агрессивными оптимизациями.

    В этом билете также говорится, что проблема затронула Java 7 и была исправлена ​​на Java 8. Они, видимо, удалили альтернативную реализацию TreeMap... хотя они не меняли javadoc.


Комментарий:

Если отслеживать проблемы (и я их правильно понял), то javadoc, вероятно, должен сказать, что метод Entry.setValue может не поддерживаться в Java 6 и Java 7. Но вводящие в заблуждение предложения могут быть полностью удалены для Java 8 и далее.

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

Ответ 2

Похоже, что указанный вами комментарий не совсем точным.

В классе TreeMap есть несколько методов, которые возвращают одиночные объекты Map.Entry: firstEntry, lastEntry, higherEntry, lowerEntry и т.д.

Я считаю, что комментарий подразумевается в отношении методов TreeMap, которые возвращают один Map.Entry. Эти методы возвращают Map.Entry, делая неизменяемую копию базовой записи (через AbstractMap.SimpleImmutableEntry).

Эти неизменяемые копии будут вызывать исключение UnsupportedOperationException, если вы вызываете их setValue.

После прочтения комментария, который вы указали, я бы подумал, что entrySet вернет неизменные копии. javadoc метода TreeMap.entrySet сообщает:

Возвращает представление Set из отображений, содержащихся в этой карте. Итератор set возвращает записи в порядке возрастания ключа. Набор поддерживается картой, поэтому изменения в карте отражаются в наборе и наоборот. Если карта изменена, когда выполняется итерация по множеству (за исключением операции собственного удаления итератора или операции setValue в записи карты, возвращаемой итератором), результаты итерации undefined. Набор поддерживает удаление элементов, которое удаляет соответствующее сопоставление с карты через операции Iterator.remove, Set.remove, removeAll, keepAll и clear. Он не поддерживает операции add или addAll.

Учитывая, что изменения в Set, возвращаемые entrySet, должны работать на базовой карте, я вижу, почему TreeMap не пытается обернуть записи - это серьезно осложнит усилия по синхронизации Sync и Set.