Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird iterator behaviour of Java HashSet

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;
  }
}
like image 739
user3001 Avatar asked Dec 05 '22 16:12

user3001


1 Answers

Each time you call iterator() it returns a new iterator, independent of any other iterators created before. So if you call hs.iterator().next() that will always give you the first element, and if you call hs.iterator().hasNext() on a non-empty collection, it will always return true.

Compare that with using it each time, which uses a single iterator throughout, therefore advancing the logical "cursor" each time you call next().

like image 169
Jon Skeet Avatar answered Dec 16 '22 14:12

Jon Skeet