1

I have a for each loop with a Set type.

While I loop through this Set I add elements to it.

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

I keep getting the ConcurrentModificationException. But I don't know how I would go about adding to this Set that wouldn't cause this exception. I can't create a new for each loop that wouldn't work.

Can anyone point me in the right direction?

7
  • 2
    @RuchiraGayanRanaweera: Iterators allow for removal of values, but not addition as far as I'm aware. Commented Jul 11, 2014 at 10:24
  • What do you mean by "I cant create a new for each loop that wouldnt work" - what exactly wouldn't work, and in what way wouldn't it work? I'd normally just build up a collection of "things to add afterwards" and add them afterwards... Commented Jul 11, 2014 at 10:25
  • What I mean is I need to use the exact same set and continuously update it. But I cant seem to figure out how to do it? Commented Jul 11, 2014 at 10:28
  • 1
    @RuchiraGayanRanaweera: You think incorrectly. Commented Jul 11, 2014 at 10:35
  • What you're trying to do is generally impossible with the standard collections. However, if you could elaborate a bit more, there might be a specific solution to your problem. Commented Jul 11, 2014 at 10:38

2 Answers 2

2

You need to either

  • use a Set which doesn't trigger a ConcurrentModifcationException e.g. ConcurrentXxxSet
  • take a copy of the set before altering it.

The simplest change is

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

With generics a simpler solution might be

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

Note: this will prevent it iterating over elements you just added. Note2: using the concurrent sets may result in you seeing added elements or possibly not.

If you really need to see elements as you add them you need to use a list, possibly instead, or as well.

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);
}

This will allow you to see elements you have added in the loop in a reliable manner. Note: some care needs to be take to not create an infinite loop and run out of memory.

An alternative is to use a queue instead of a list. This might be nicer, but I suspect less efficient.

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);
}
Sign up to request clarification or add additional context in comments.

1 Comment

How much less efficent is the queue? I am handling large amounts of data hence the reason I want to use a Set?
0

You could make a temporary Set and add your elements to this temp Set, and when you finished lopping over all elements, add the values from the temp Set to the original Set

Example:

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); 

5 Comments

But how do I keep looping through the originalSet? I dont want it to stop
what do you mean with keep looping? it will keep looping through all items in your originalSet. Or should it also loop through the items which I add to the tempList?
Yes it also needs to loop through the items in the temp list as well and keep going till no more items are added? Works fine with arraylists trying to get it to work with sets
So, why would you like to use a Set?
Efficency and speed :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.