Today I ran into some weird behaviour with a HashSet’s iterator.
In the code example below, idString uses an object reference returned by hs.iterator to call the iterator’s next() method.
In idString2the iterator is called via hs.iterator() and it does not work anymore.
So I assume that HashSet.iterator() returns a new iterator object each time it is called. But then, why can I still use hs.iterator().hasNext() in the while loop?
(Note that the code below is just an example 🙂 )
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import org.junit.Test;
public class DummyTest {
static final HashSet<Integer> TEST_DATA = new HashSet<Integer>(
Arrays.asList(new Integer[] {
1,2,3,4,5,6,7,8,9,10
}));
@Test
public void testRunTest() {
// Correct output: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
System.out.println(idString(TEST_DATA));
// Only 1, 1, 1, 1, ...
System.out.println(idString2(TEST_DATA));
}
static String idString(HashSet<Integer> hs) {
Iterator<Integer> it = hs.iterator();
String res = it.next() + "";
while (it.hasNext()) {
res += ", " + it.next();
System.out.println(res); // debug
}
return res;
}
static String idString2(HashSet<Integer> hs) {
Iterator<Integer> it = hs.iterator();
// Prevent an infinite loop
int i = 0;
String res = null;
res = it.next() + "";
while (hs.iterator().hasNext() && i++ <= 10) {
// if replacing hs.iterator() with 'it', it works
res = res + ", " + hs.iterator().next();
System.out.println(res); // debug
}
return res;
}
}
Each time you call
iterator()it returns a new iterator, independent of any other iterators created before. So if you callhs.iterator().next()that will always give you the first element, and if you callhs.iterator().hasNext()on a non-empty collection, it will always returntrue.Compare that with using
iteach time, which uses a single iterator throughout, therefore advancing the logical “cursor” each time you callnext().