I wish to iterate over a set but the contents of the set will modify during its iteration. I wish to iterate over the original set at the time the iterator was created and not iterate over any of the new elements added to the set. How is this possible? Is this is the default behavior of set or how can I accomplish this?
One way I can think of is to get a new set from the original set which won't be modified but this seems inelegant and there must be a better solution.
It is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances.
Because you iterate over a copy of the list, you can modify the original list without damaging the iterator.
You can use while or for loop along with hasNext(), which returns true if there are more elements in the Set. Call the next() method to obtain the next elements from Set.
In for-each loop, we can't modify collection, it will throw a ConcurrentModificationException on the other hand with iterator we can modify collection.
Taking a snapshot of the set sounds like exactly the right solution to me, if you want to make sure you don't see any new elements. There are some sets such as ConcurrentSkipListSet
which will allow you to keep iterating, but I can't see any guarantees around behaviour of an iterator in terms of seeing new elements.
EDIT: CopyOnWriteArraySet
has the requirements you need, but writes are expensive, which sounds like it's not appropriate for you.
Those are the only sets I can see in java.util.concurrent
, which is the natural package for such collections. Taking a copy is still likely to be simpler :)
EDIT: This answer was designed for a single-threaded case, since I had interpreted the OP's question as avoiding comodification rather than avoiding issues from multithreading. I'm leaving this answer here in case it ends up being useful to anyone in the future who is using a single-threaded approach.
There is no direct way to accomplish this. However, one option that is quite nice is to have two sets - the main set, which you iterate over, and a secondary set into which you insert all the new elements that need to be added. You can then iterate over the primary set, and then once that's finished go and use addAll
to add all the new elements to the primary set.
For example:
Set<T> masterSet = /* ... */
Set<T> newElems = /* ... */
for (T obj: masterSet) {
/* ... do something to each object ... */
}
masterSet.addAll(newElems);
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With