Безопасно ли добавлять элементы в SortedSet во время итерации?
Безопасно ли добавлять элементы в модифицируемый SortedSet
перебирая этот набор? В частности, безопасно ли добавлять элементы в набор позже, чем элемент, указанный итератором?
Например, будет ли следующий код повреждать SortedSet s
или выбросить исключение (которое, вероятно, будет ConcurrentModificationException
):
/**
* s not null, is modifiable.
*/
private final addSelectedFollowers(final SortedSet<Integer> s)
{
for (Integer i: s) {
if (shouldAddNext(i)) {
s.add(i + 1);
}
}
}
protected abstract boolean shouldAddNext(int i);
Я предполагаю, что это безопасно, но я не могу найти четкое утверждение в документации JRE API. Я знаю, что если поведение не указано, реализация может свободно выбирать поведение. Отсутствие явного заявления в документации SortedSet
недостаточно ответить на вопрос так или иначе; требуемое поведение может быть указано косвенно в документации для другого класса или интерфейса. К сожалению, в документах JRE не всегда четко указано, что разрешено. Поэтому я ищу ответы, которые ссылаются на JRE API, а не на лёгкое утверждение " да" или " нет". Я также знаю, что SortedSet
может быть сделано неизменяемым, что сделало бы SortedSet.add()
потерпеть поражение; Я заинтересован в случае изменяемого SortedSet
,
Обратите внимание, что я спрашиваю о добавлении элементов в набор, а не об изменении элементов в наборе.
2 ответа
Если поведение не указано, реализация может свободно выбирать поведение.
Например, два класса, перечисленные как известные классы реализации в Javadoc, реализуют оба поведения:
ConcurrentSkipListSet
:Итераторы слабо согласованы, возвращая элементы, отражающие состояние множества в некоторой точке во время или после создания итератора. Они не генерируют исключение ConcurrentModificationException и могут выполняться одновременно с другими операциями.
TreeSet
:Итераторы, возвращаемые методом итератора этого класса, не подвержены сбоям: если набор изменяется в любое время после создания итератора, любым способом, кроме как через собственный метод удаления итератора, итератор генерирует исключение ConcurrentModificationException.
Тем не менее, более фундаментально, Collection.add
(а также Set.add
) задокументирована как необязательная операция, поэтому мы никогда не можем полагаться на вызов SortedSet.add
быть в безопасности, независимо от того, происходит ли в контексте продолжающаяся итерация или нет.
Например, позвонив add
на SortedSet
вернулся Collections.unmodifiableSortedSet
или гуава ImmutableSortedSet
приведет к UnsupportedOperationException
,
Это зависит от реализации. Например, в случае TreeSet
, итераторы отказоустойчивы, поэтому добавление элементов во время итерации вызовет ConcurrentModificationException
,
Из JavaDoc TreeSet
:
Итераторы, возвращаемые методом итератора этого класса, не подвержены сбоям: если набор изменяется в любое время после создания итератора, любым способом, кроме как через собственный метод удаления итератора, итератор генерирует исключение ConcurrentModificationException. Таким образом, перед одновременной модификацией итератор быстро и чисто дает сбой, вместо того, чтобы рисковать произвольным недетерминированным поведением в неопределенное время в будущем.
В других реализациях с итераторами, не подверженными сбоям, можно добавлять элементы во время итерации.