Java: Iterating over a set when the contents of a set change

I want to iterate over a set, but the contents of the set will change during iteration. I want to iterate over the source set while creating an iterator and not iterate over any of the new elements added to the set. How is this possible? Is this the default behavior for a set or how to do it?

One way that I can think of is to get a new set from the original set, which will not be changed, but it seems inelegant, and there should be a better solution.

+7
source share
6 answers

Taking a snapshot of a set sounds like the right solution for me if you want to make sure you don't see any new items. There are several sets, such as ConcurrentSkipListSet , that will allow you to continue to iterate, but I see no guarantees regarding the behavior of the iterator in terms of viewing new elements.

EDIT: CopyOnWriteArraySet has the requirements you need, but writing is expensive, which doesn't seem right for you.

These are the only sets that I can see in java.util.concurrent , which is a natural package for such collections. Getting a copy will still be easier :)

+8
source

EDIT:. This answer was designed for a single-threaded case, since I interpreted the OP question as avoiding codification, and not avoiding problems from multithreading. I leave this answer here if it proves useful for anyone in the future who uses a single-threaded approach.

There is no direct way to accomplish this. However, one option that is pretty good is to have two sets - the main set that you iterate over and the secondary set into which you insert all the new elements that you need to add. You can then iterate over the main set, and then after that go and use addAll to add all the new elements to the main set.

For example:

 Set<T> masterSet = /* ... */ Set<T> newElems = /* ... */ for (T obj: masterSet) { /* ... do something to each object ... */ } masterSet.addAll(newElems); 

Hope this helps!

+7
source

Making a copy of Set is an elegant solution.

 Set<Obj> copyOfObjs = new HashSet<Obj>(originalSet); for(Obj original : originalSet) { //add some more stuff to copyOfObjs } 
+2
source

You can use ConcurrentHashMap with dummy keys. Or ConcurrentSkipListSet

0
source

Now that the OP has clarified the requirements, the solutions

  • Copy set before iteration
  • Use CopyOnWriteArraySet
  • Write your own code and try to be smarter than many smart people.

The drawback # 1 is that you always copy the set, even if it might not be needed (for example, if there really aren’t any attachments when you iterate), I suggest option 2, unless you prove that frequent inserts cause a real problem with performance.

0
source

As others have suggested, there is no optimal solution for what you are looking for. It all depends on the use case of your application or the use of the kit.
Since Set is an interface, you can define your own DoubleSet class that will implement Set and let, say, use two HashSet fields.
When you retrieve an iterator, you should note that one of these sets is in interaction-only mode, so the add method will only add to the other set


I'm still new to Stackoverlflow, so I need to understand how to embed code in my answers: (but in general you should have a class called MySet (Generic of generic type T) that implements Set generic type T.
You need to implement all the methods and have two fields: one called iterationSet and the other called insertionSet.
You will also have a boolean field indicating whether to insert these two sets or not. When the iterator () method is called, this boolean value must be set to false, that is, you should only insert into the insertingSet.
You should have a method that will synchronize the contents of the two sets as soon as you are done with the iterator.
I hope I was clean.

0
source

All Articles