I need to iterate over the set of values for each iteration of for loop, but only for first iteration it works fine. Thereafter the itr.hasNext()
returns
You can only iterate an Iterator once.
If you need to "reset" it, and recreating the Iterator is expensive (such as reading from a file), you could copy the data into a temporary Collection (such as an ArrayList). But that requires enough memory to hold everything at once.
Another approach could be (depends on what your program does) to swap the order of loop nesting: Iterate over your iterator just once, and over your Person
s in the inner loop (since you already have all those in memory). Obviously, this processes things in a different order which may or may not be easy to accomodate for you.
It depends on the exact contents of your code block, but why not flip the loops? Have the outer loop go over the file, and for each iteration, go over all the Person
s:
Iterator<String> itr = getQuestionIterator(File file);
while(itr.hasNext())
{
String question = itr.next();
for(Person p : persons)
{
........
........
}
}
An Iterator
is the smallest possible API to work off data sequentially, hence it abstracts from the underlying data source. As it can only move forwards (next()
) without any option to reset or rewind, it is a one-way object that must be thrown away after usage. And due to the limited API it offers, it is not possible to simply "copy" it without knowing the implementation and/or the underlying data source.
So there are four ways to handle your problem:
(1) Re-aquire a new iterator from the underlying data source
Just call getQuestionIterator(File file)
every time you need to iterate over the data (again).
(2) Combine all processing code into one single iterating loop
Instead of...
while (iterator.hasNext()) { /* first processing step */ }
while (iterator.hasNext()) { /* second processing step */ }
while (iterator.hasNext()) { /* third processing step */ }
...
...combine all steps:
while (iterator.hasNext()) {
String question = iterator.next();
/* first processing step */
/* second processing step */
/* third processing step */
...
}
(3) Copy all elements into a local cache (Collection
)
Iterate over all items once and put them into a local collection that you can use to aquire an arbitrary number of iterators:
// read everything into a local cache
Collection<String> cache = new ArrayList<>();
while (iterator.hasNext()) cache.add(iterator.next());
// now you can get as many iterators from cache as required:
Iterator<String> iter = cache.iterator();
// use iter
iter = cache.iterator(); // once more
// use iter
...
(4) Modify your data source API to let its implementation handle the problem
Meaning: Change getQuestionIterator(File file)
to return an Iterable<String>
instead of an Iterator<String>
. You can gain an arbitrary number of iterators from an Iterable
:
Iterable<String> iterable = getQuestionIterator(File file);
Iterator<String> iter = iterable.iterator();
// use iter
iter = iterable.iterator(); // once more
// use iter