-1

Could someone explain to me why the following doesn't work (runways is a Hibernate PersistentSet) ?

System.out.println("size before " + runways.size());
Iterator<Runway> deleteIterator = runways.iterator();
while (deleteIterator.hasNext()) {
    Runway rwy = deleteIterator.next();
    if (rwy == rwy3) {
        System.out.println("remove !");
        deleteIterator.remove();
    }
}
System.out.println("size after " + runways.size());

I get the system.Out logs:

INFO: size before 3
INFO: remove !
INFO: size after 3

I thought that deletion through the iterator was safe and possible. You see the log "remove"! which indicates that the remove() method is called.

EDIT : PersistentSet has problem with the remove method from the Iterator interface.

facewindu
  • 665
  • 2
  • 11
  • 27

4 Answers4

3

Check to make sure your hashCode() and equals() methods are overridden and correct on your Runway object.

JustinKSU
  • 4,547
  • 2
  • 24
  • 48
  • 1
    He's seeing the `System.out` be called, which would indicate that he is already in the `if` block. – Nicholas May 01 '13 at 16:12
  • 1
    Since it enters the `if` block, this is not a problem. – Konstantin Yovkov May 01 '13 at 16:13
  • 1
    No, this is a very relevant issue – Rob Watts May 01 '13 at 16:14
  • @RobWatt I think I see what you are saying. The `HashMap$HashIterator` class has the `remove()` method for the iterator, and that performs a remove based on the `hashCode()` and `equals()`, is that a valid assumption? – Nicholas May 01 '13 at 16:21
  • He enters the if block because he is using == which checks to see if it's the same instance of the class. remove() uses .equals() which is different. – JustinKSU May 01 '13 at 20:07
  • To further explain, there is no guarantee the List implementation uses == although it should. Seems the problem IS related to the implementation of the List (see @user1446127 answer) – JustinKSU May 01 '13 at 20:15
3

//EDIT: FYI this code is an example of failing code. Override your equals() and hashCode() properly.

To follow up on JustinKSU's point, if you don't implement your hashCode() and equals() well, what you are doing won't work. I can replicate your situation if I muddy the equals() and the hashCode().

public static void main(String[] args) {
    Set<Runway> runways = new HashSet<Runway>();
    Runway rwy1 = new Runway();
    Runway rwy2 = new Runway();
    Runway rwy3 = new Runway();
    runways.add(rwy1);
    runways.add(rwy2);
    runways.add(rwy3);
    System.out.println("size before " + runways.size());
    Iterator<Runway> deleteIterator = runways.iterator();
    while (deleteIterator.hasNext()) {
        Runway rwy = deleteIterator.next();
        if (rwy == rwy3) {
            System.out.println("remove !");
            deleteIterator.remove();
        }
    }
    System.out.println("size after " + runways.size());
}

private static class Runway {
    @Override
    public boolean equals(Object obj) {
        return false;
    }

    @Override
    public int hashCode() {
        return (new Random()).nextInt();
    }
}
Nicholas
  • 7,205
  • 8
  • 44
  • 72
0

From looking at the JDK source code (I found it here), the iterator returned by a HashSet uses one of the HashSet's internal remove methods for performing the actual removal.

For a HashSet to work correctly, you need to either leave both equals and hashCode in your Runway class alone, or override them both. This SO question talks about this issue: What issues should be considered when overriding equals and hashCode in Java?

Community
  • 1
  • 1
Rob Watts
  • 6,260
  • 2
  • 31
  • 57
0

My equals and hashCode methodes were created by Eclipse itself. So it doesn't come from them.

But I was too quick at the beginning of my question. I forgot that Runways is a PersistentSet from Hibernate (and not a java.util.HashSet)

And I found this bug which explaines why it is not possible to remove a object from a PersistenSet iterator.

The bug seems old and complicated to solve. My only option is then to recreate a set from the first one, and without the element I don't want.

facewindu
  • 665
  • 2
  • 11
  • 27