The answer to this SO explains the issue I'm having: HashSet.remove() and Iterator.remove() not working
Basically, once I add something to the HashSet, if I modify any of its fields, then the set will fail any equality tests with a set containing an object with the exact same fields, since the hash code it was stored in was for when it had different fields set.
So, since that answer explains what's going on, what would be a good workaround for this to have both the uniqueness of using a set and be able to modify internal fields of the objects in the set? Or is this just not possible?
Of course it has, and it can! In fact, hash keys is all the HashSet has -- just keys, no values. In a HashMap the "value" is passive: that's something stored at the key; hash maps never look at values; in particular, maps never check values for equality, or compute their hash code.
add) hash (derived from hashcode) is equal to already stored element in the HashMap and it is equal to already stored element or equals method if called on two returns true, the object will not be stored into the HashSet or the key will not be stored into the HashMap.
HashSet is backed by a HashMap internally, but the element you are adding to the HashSet is used as the key in the backing HashMap . For the value, a dummy value is used. Therefore the HashSet 's contains(element) simply calls the backing HashMap 's containsKey(element) .
HashSet extends AbstractSet and implements the Set interface. It creates a collection that uses a hash table for storage. A hash table stores information by using a mechanism called hashing. In hashing, the informational content of a key is used to determine a unique value, called its hash code.
If the fields that you modify are not part of the equality test, they should not be part of the hash code computation either. In that case there's no problem: you can just modify those fields.
If the fields are part of the equality test, the cleanest way is probably to remove the object from the set, then modify and re-insert it.
If it's the latter, and you find yourself doing this a lot, you might want to re-visit the choice of data structure for the problem at hand.
Remove the object you want to modify from the set, change it, and then add it back. As far as I know there is no standard Set
implementation that can cope with fields (that are used in either the hashCode()
or compareTo()
implementation) being changed while it is stored.
Alternatively, if the fields aren't used in determining identity, equality or location (i.e. not used in hashCode()
, compareTo
or equals()
) then there is no problem.
The only way to work around it would be to not have a hashCode()
method that depends on any mutable fields. If objects have an identity and existence that's independent of the values of its fields, then this is easy -- use System.identityHashCode()
. Otherwise, you might base the hashCode()
on one single non-mutable field. If there isn't one, then I'm afraid you're out of luck.
Use HashMap instead of HashSet. Define key as something unique that willn't change in the time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With