Наборы и ConcurrentModificationException

1

У меня есть для каждого цикла с типом Set.

Пока я просматриваю этот набор, я добавляю к нему элементы.

 for (Object o: Set) {
    //i do something and add to the set
  }

Я продолжаю получать ConcurrentModificationException. Но я не знаю, как бы я добавил к этому Set, что не вызвало бы этого исключения. Я не могу создать новый для каждого цикла, который бы не работал.

Может кто-то указать мне верное направление?

  • 1
    @RuchiraGayanRanaweera: насколько я знаю, итераторы позволяют удалять значения, но не добавлять .
  • 0
    Что вы подразумеваете под «я не могу создать новый для каждого цикла, который не будет работать» - что именно не будет работать, и каким образом это не будет работать? Обычно я просто собираю коллекцию «вещей, которые нужно добавить потом» и добавляю их потом…
Показать ещё 5 комментариев
Теги:
set
loops
foreach

2 ответа

2

Вам нужно либо

  • используйте Set, который не вызывает ConcurrentModifcationException, например ConcurrentXxxSet
  • возьмите копию набора, прежде чем изменять его.

Простейшим изменением является

for (Object o: set.toArray()) {
    if (condition(o))
       set.add(something);
}

С помощью дженериков более простым решением может быть

Set<T> set = 
for(T t: new HashSet<T>(set)) {
   // something which might add to set
}

Примечание. Это предотвратит повторение итерации элементов, которые вы только что добавили. Примечание2: использование параллельных наборов может привести к появлению добавленных элементов или, возможно, нет.

Если вам действительно нужно видеть элементы при их добавлении, вам нужно использовать список, возможно, вместо этого, а также.

List<T> list = new ArrayList<>(set);

for(int i = 0; i < list.size(); i++) {
    T t = list.get(i);

    if (condition)
        // if it is not a duplicate
        if (set.add(something))
            list.add(something);
}

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

Альтернативой является использование очереди вместо списка. Это может быть приятнее, но я считаю менее эффективным.

Queue<T> q = new ConcurrentLinkedQueue<>(set);

for(T t : q) {
    if (condition)
        // if it is not a duplicate
        if (set.add(something))
            q.add(something);
}
  • 0
    Насколько менее эффективна очередь? Я работаю с большими объемами данных, поэтому я хочу использовать Set?
0

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

Пример:

Set<Integer> originalSet;
//stuff where you fill your original Set
Set<Integer> tempSet = new Set<Integer>();

for(Integer i : originalSet) {
    tempSet.add(<integerToAdd>);
}
originalSet.addAll(tempSet); 
  • 0
    Но как мне продолжать цикл через оригинальный набор? Я не хочу, чтобы это прекратилось
  • 0
    Что ты имеешь в виду, продолжая цикл? он будет продолжать проходить по всем элементам в вашем оригинальном наборе. Или он также должен перебирать элементы, которые я добавляю в tempList?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню