2

I have an object in a LinkedHashSet that implements equals, hashCode and compareTo (in a superclass) but when I try to remove that exact object from the set set.remove(obj) the remove method returns false and the object remains in the set. Is the implementation of LinkedHashSet supposed to call the equals() method of its objects? Because it doesn't. Could this be a java bug? I'm running 1.6.0_25.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
mekazu
  • 2,545
  • 3
  • 23
  • 21
  • 4
    [First rule of programming: It's always your fault](http://www.codinghorror.com/blog/2008/03/the-first-rule-of-programming-its-always-your-fault.html) Without seeing your code, we can't tell you what you're doing wrong. – Brian Roach Oct 26 '11 at 02:10
  • 4
    Please hold a mirror up in front of your webcam so I can see your code. Oh, and reverse all the windows so I don't have to read it backwards. At this point I'm... skeptical it's a Java bug. – Dave Newton Oct 26 '11 at 02:11
  • Post here the code of `equals()` and `hashCode()` – Óscar López Oct 26 '11 at 02:11
  • Test `equals` on the object you are passing to remove and the object you think should be removed first. – Ray Toal Oct 26 '11 at 02:13
  • A `HashSet` removes an element if they are `equal()`. http://download.oracle.com/javase/6/docs/api/java/util/HashSet.html#remove(java.lang.Object) – tskuzzy Oct 26 '11 at 02:14

3 Answers3

6

My guess would be that your object's hashCode() implementation is returning a different value than when you added the object to the set.

Stephen Denne
  • 36,219
  • 10
  • 45
  • 60
  • 1
    Which is why we're asking to see the code--not really an answer yet ;) – Dave Newton Oct 26 '11 at 02:14
  • @Dave well my reasoning is that mekazu says equals() isn't being called, which it wouldn't be if the object wasn't found by its hash due to the hash changing. – Stephen Denne Oct 26 '11 at 02:20
  • Not saying you're wrong, saying it's premature :) Could just be the object's state is changing, too--who knows. – Dave Newton Oct 26 '11 at 02:22
  • @mekazu in Oracle's 1.6.0_25 LinkedHashSet, both contains() and remove() end up mapping the hashCode() of the supplied object to an index in an array. The hash is compared to the hash of the entries found there, since multiple hashes can map to the same index, and if the hash is the same, then the equals method is called. If your objects are equal, they should return the same hashcode, as per the javadocs on hashCode() – Stephen Denne Oct 26 '11 at 02:32
  • Correct! The object key was added to the object after it was inserted into the Set. Thus hashCode returned a different value to when it was first added. It's strange that the [javadoc](http://download.oracle.com/javase/6/docs/api/java/util/HashSet.html#remove(java.lang.Object)) doesn't make mention of this caveat. – mekazu Oct 26 '11 at 02:38
  • 1
    That 'caveat' is mentioned in the javadoc of hashCode() on Object: "[..] invoked on the same object more than once [..], the hashCode method must consistently return the same integer, [..]" – Mark Rotteveel Oct 26 '11 at 12:43
0

LinkedHashSet works fine for me:

import java.util.*;

public class Test {
    public static void main( String[] args ) {
        LinkedHashSet<String> lhs = new LinkedHashSet<String>();
        String s = "hi";
        lhs.add( s );
        System.out.println( lhs );
        lhs.remove( s );
        System.out.println( lhs );
    }
}

Perhaps you're passing in a reference to a different object to the remove method? Are you sure you didn't change the reference in any way?

Also make sure that hashCode() returns the same value when you insert it as when you are trying to remove it.

tskuzzy
  • 35,812
  • 14
  • 73
  • 140
0

The chances of this being a bug in LinkedHashSet are infinitessimnally small. You should dismiss this as a plausible explanation of your problem.

Assuming that this is a bug in your code, then it could be due to a number of things. For instance:

  • Your equals and hashCode methods are returning contradictory answers for the object.
  • Your equals or hashCode methods depend on mutable fields and those fields are being changed while the object is in the set. (For instance, if the hashcode value changes, the object is likely to be on the wrong hash chain, causing the remove method to not find it.)
  • You have declared the equals method as an overload, not an override of equals(Object). (That could explain why your equals is not being called ... assuming that your assertion is factually correct.)
  • The object you are trying to remove is (in reality) not the one you inserted.
  • Something else has already removed the object.
  • You are running a different version of some class that does not match the source code you have been examining.

Now, I know that you have dismissed some of these explanations. But that may have been premature. Review the evidence that you based that dismissal on.

Another approach you could use is to use a Java debugger to forensically examine the data structures (e.g. the innards of the LinkedHashSet) and single-step the code where the deletion is supposed to be happening.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216