Is it possible to add elements to a collection while iterating over it?
More specifically, I would like to iterate over a collection, and if an element satisfies a certain condition I want to add some other elements to the collection, and make sure that these added elements are iterated over as well. (I realise that this could lead to an unterminating loop, but I'm pretty sure it won't in my case.)
The Java Tutorial from Sun suggests this is not possible: "Note that Iterator.remove
is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress."
So if I can't do what I want to do using iterators, what do you suggest I do?
There are two issues here:
The first issue is, adding to an
Collection
after anIterator
is returned. As mentioned, there is no defined behavior when the underlyingCollection
is modified, as noted in the documentation forIterator.remove
:The second issue is, even if an
Iterator
could be obtained, and then return to the same element theIterator
was at, there is no guarantee about the order of the iteratation, as noted in theCollection.iterator
method documentation:For example, let's say we have the list
[1, 2, 3, 4]
.Let's say
5
was added when theIterator
was at3
, and somehow, we get anIterator
that can resume the iteration from4
. However, there is no guarentee that5
will come after4
. The iteration order may be[5, 1, 2, 3, 4]
-- then the iterator will still miss the element5
.As there is no guarantee to the behavior, one cannot assume that things will happen in a certain way.
One alternative could be to have a separate
Collection
to which the newly created elements can be added to, and then iterating over those elements:Edit
Elaborating on Avi's answer, it is possible to queue up the elements that we want to iterate over into a queue, and remove the elements while the queue has elements. This will allow the "iteration" over the new elements in addition to the original elements.
Let's look at how it would work.
Conceptually, if we have the following elements in the queue:
[1, 2, 3, 4]
And, when we remove
1
, we decide to add42
, the queue will be as the following:[2, 3, 4, 42]
As the queue is a FIFO (first-in, first-out) data structure, this ordering is typical. (As noted in the documentation for the
Queue
interface, this is not a necessity of aQueue
. Take the case ofPriorityQueue
which orders the elements by their natural ordering, so that's not FIFO.)The following is an example using a
LinkedList
(which is aQueue
) in order to go through all the elements along with additional elements added during the dequeing. Similar to the example above, the element42
is added when the element2
is removed:The result is the following:
As hoped, the element
42
which was added when we hit2
appeared.For examle we have two lists:
a1 b1 a2 b2 a3 b3 a4 b4 a5 b5
You may also want to look at some of the more specialised types, like ListIterator, NavigableSet and (if you're interested in maps) NavigableMap.
IMHO the safer way would be to create a new collection, to iterate over your given collection, adding each element in the new collection, and adding extra elements as needed in the new collection as well, finally returning the new collection.
Use
ListIterator
as follows:The key is to iterate in reverse order - then the added elements appear on the next iteration.
Using iterators...no, I don't think so. You'll have to hack together something like this:
Which yeilds:
[foo, bar, baz, added-item-1, added-item-2]