AHungerArtist
AHungerArtist

Reputation: 9609

Workaround for hash for a HashSet when the internal object changes

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?

Upvotes: 8

Views: 2113

Answers (5)

Matthias Ronge
Matthias Ronge

Reputation: 10122

Use any other collection (maybe a LinkedList), and check for uniqueness only at the moment of adding, like in

public class MySetList<E> extends LinkedList<E> implements Set<E> {
    private static final long serialVersionUID = 1L;

    @Override
    public boolean add(E e) {
        return new HashSet<E>(this).add(e) ? super.add(e) : false;
    }
}

Upvotes: -1

NPE
NPE

Reputation: 500923

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.

Upvotes: 8

alexsmail
alexsmail

Reputation: 5813

Use HashMap instead of HashSet. Define key as something unique that willn't change in the time.

Upvotes: 1

Ernest Friedman-Hill
Ernest Friedman-Hill

Reputation: 81724

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.

Upvotes: 3

Mark Peters
Mark Peters

Reputation: 81164

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.

Upvotes: 7

Related Questions