Iteration order of HashSet

后端 未结 9 857
眼角桃花
眼角桃花 2020-11-27 07:32

If every object added to a java.util.HashSet implements Object.equals() and Object.hashCode() in a deterministic fashion, is the iteration order over the HashSet guaranteed

相关标签:
9条回答
  • 2020-11-27 07:54

    Never ever make assumptions about the iteration order of anything you put into a HashSet because its contract explicitly says that you can't count on it in any way. Use LinkedHashSet if you want to maintain insertion order or TreeSet if you want to maintain a natural sorting order.

    0 讨论(0)
  • 2020-11-27 08:03

    Absolutely not.

    The insertion order directly influences the iteration order whenever you have a bucket collision:

    When two elements end up in the same bucket, the first one that was inserted will also be the first one returned during iteration, at least if the implementation of collision handling and iteration is straightforward (and the one in Sun's java.util.HashMap is)

    0 讨论(0)
  • 2020-11-27 08:06

    As per the javadoc:

    This class implements the Set interface, backed by a hash table (actually a HashMap instance). It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time. [...] The iterators returned by this class's iterator method are fail-fast: if the set is modified at any time after the iterator is created

    And the method iterator:

    Returns an iterator over the elements in this set. The elements are returned in no particular order.

    So I don't think you can make such an assumption.

    0 讨论(0)
  • 2020-11-27 08:06

    The order objects appear will depend on the final number of buckets of the HashSet. By changing the load factor and/or initial capacity you can change the order the elements end up in.

    In the following example, you can see these confirguations each result in a different order.

    public static void main(String...args) throws IOException {
        printOrdersFor(8, 2);
        printOrdersFor(8, 1);
        printOrdersFor(8, 0.5f);
        printOrdersFor(32, 1f);
        printOrdersFor(64, 1f);
        printOrdersFor(128, 1f);
    }
    
    public static void printOrdersFor(int size, float loadFactor) {
        Set<Integer> set = new HashSet<Integer>(size, loadFactor);
        for(int i=0;i<=100;i+=10) set.add(i);
        System.out.println("new HashSet<Integer>("+size+", "+loadFactor+") adding 0,10, ... 100 => "+set);
    }
    

    prints

    new HashSet<Integer>(8, 2.0) adding 0,10, ... 100 => [0, 50, 100, 70, 40, 10, 80, 20, 90, 60, 30]
    new HashSet<Integer>(8, 1.0) adding 0,10, ... 100 => [0, 50, 100, 70, 20, 80, 10, 40, 90, 30, 60]
    new HashSet<Integer>(8, 0.5) adding 0,10, ... 100 => [0, 100, 70, 40, 10, 50, 20, 80, 90, 30, 60]
    new HashSet<Integer>(32, 1.0) adding 0,10, ... 100 => [0, 100, 70, 40, 10, 50, 80, 20, 90, 60, 30]
    new HashSet<Integer>(64, 1.0) adding 0,10, ... 100 => [0, 70, 10, 80, 20, 90, 30, 100, 40, 50, 60]
    new HashSet<Integer>(128, 1.0) adding 0,10, ... 100 => [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
    
    0 讨论(0)
  • 2020-11-27 08:08

    No, this is not guaranteed.

    First, different JVM may implement the HashSet algorithm differently (as long as it complies with the HashSet specification) so you will get different results on different JVMs.

    Second, the algorithm may rely on non-deterministic factors when it builds the different buckets (part of the hash-table algorithm).

    0 讨论(0)
  • 2020-11-27 08:14

    There is no "official" guarantee for anything like this. I would say it is most probably true for instances of the same HashSet implementation, initialized the same way. But I have seen cases for the iteration order being different between Java 5 and 6, for example.

    Also, it may be different for instances of the same HashSet implementation, initialized with different size, due to rehashing. I.e. if you have 100 elements and two sets, one initialized with a size greater than 100, the other with a much smaller size, the second one will get reallocated and its elements rehashed several times while filling up. This may result in elements mapped to the same bucket being added (and thus iterated over) in different order.

    In Java4 and later, you have LinkedHashSet which guarantees that the iteration order will be the order in which its elements were inserted.

    0 讨论(0)
提交回复
热议问题