Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the order of elements in HashSet's keySet changes from run to run?

Tags:

java

I have some code utilizing standard Java collections: arrays, ArrayDeques, HashMaps, Lists, HashSets. My code is expected to be deterministic: the hash codes of all the elements, the initial contents of the collections, and etc. are expected to depend only on the input data. The final output of the code is produced from a keySet() of some HashMap.

I've noticed that the order of the elements in the resulting keySet sometimes changes from run to run. What does it mean?

  • Some standard collections have non-deterministic behavior (e.g., hash codes of some internal objects are non-deterministic)?
  • My own code is actually non-deterministic (e.g., I forgot to properly override hashCode() for some class)? This might mean I have a bug somewhere (that wasn't caught by the tests yet), that's why I'm concerned.
  • Something else?

This happens quite consistently with JDK 1.7.0_60, x86 on Windows 7 x64. Allegedly, this does not happen (or happens rarely) with JDK 1.8.0_05. Also, the order of elements in the resulting keySet (and the overall order in which the data items are processed) changes when switching between the above JDKs.

I suspect, this is some feature of a HashSet, but could not trace it to a specific line of code.

UPD 1 I do not really need deterministic sets, and I know that HashSet provides no guarantees. I'm just trying to find the reason of non-deterministic behavior. If it is in library code - fine. But if it is in my code - I'll likely have to fix it. Hence the question.

UPD 2 Of course, I managed to find the answer right after posting the question. Just in the beginning of 1.7's HashMap.java:

/**
 * A randomizing value associated with this instance that is applied to
 * hash code of keys to make hash collisions harder to find. If 0 then
 * alternative hashing is disabled.
 */
transient int hashSeed = 0;

In 1.8, this randomization doesn't seem to be there any more.

like image 744
Alexey B. Avatar asked Jul 16 '14 03:07

Alexey B.


People also ask

Does HashSet change order?

But when put into HashSet, it has its own order base on hashcode of elements, it means if all elements have unique hashcode, you run 1000 times, the orders are always the same! You see? No Alphabet order! if you run 1000 times, the orders are always the same: No.

How does HashSet maintain order?

HashSet does not provide any method to maintain the insertion order. Comparatively, LinkedHashSet maintains the insertion order of the elements. We can not predict the insertion order in HashSet, but we can predict it in LinkedHashSet. The LinkedHashSet extends the HashSet, so it uses a hashtable to store the elements.

Does HashSet store elements in order?

It means that HashSet does not maintains the order of its elements. Hence sorting of HashSet is not possible.

Is order preserved in HashSet?

No, a hash set won't preserve insertion order, at least not predictably. You could use a LinkedHashSet (Java), or an equivalent. A LinkedHashSet will preserve order. If you want order, you shouldn't even be using a set in the first place... its not made for ordered elements, except in exceptional cases.


1 Answers

From the documentation of HashSet:

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.

like image 148
AntonH Avatar answered Oct 04 '22 18:10

AntonH