• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Duplicates in a Set

 
Yaroslav Ashurin
Greenhorn
Posts: 22
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dear All,
I'm missing something. Please consider the situation:

import java.util.*;

class ASet {

public static void main(String[] args) {

Set<Drink> set = new HashSet<Drink>();

Drink one = new Drink("Soda");

Drink two = new Drink("Tonic");

Drink three = new Drink("Vodka");

set.add(one);

set.add(two);

set.add(three);

System.out.println(set); // printed {Soda, Tonic, Vodka}, no problem

one.name = "Vodka";

System.out.println(set); // printed {Tonic, Vodka, Vodka} Duplicates?

} //end main

} //end class

And Drink class overrides equals(), hashCode() and toString() this way:

class Drink {

String name;

public int hashCode() {

return name.hashCode(); // since String overrides the hashCode()

}

public boolean equals(Object drink) {

return name.equals((Drink)drink.name);

}

public String toString() {

return name;

}

}

Question is: how it's possible to have entries in a Set that look identical? Thank you.
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Did you read the Javadoc for Set ?
Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set. A special case of this prohibition is that it is not permissible for a set to contain itself as an element.
 
Yaroslav Ashurin
Greenhorn
Posts: 22
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Joanne,

sure I read the note in API, and still can't figure out what's going on in the set. When you try to delete all the items one at a time like this:

set.remove(one);
set.remove(two);
set.remove(three);

the set does not get empty, there is kinda "ghoast" element left behind, that is set.size() returns 1, not zero, after removal of all the items. Could you please explain it? Thank you so much.
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
... The behavior of a set is not specified ...
This means that you cannot rely on what will happen in these circumstances. As you have found, maybe you will be unable to remove all the elements from the Set. This is what happens for the Set implementation that you are using. A different implementation might have removed both elements that matched. Another implementation might remove neither of them. Yet another implementation might do something else.
The point is that you cannot rely on the behaviour and so you should avoid such situations.
 
Wirianto Djunaidi
Ranch Hand
Posts: 210
Ruby Ubuntu VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yaroslav,

The problem is because you changed the content of Drink after it is already added into the Set. Set only prevent adding duplicate into it, so the check is done when you call add() method.

Since your object one is already in the Set, you can change the name to a duplicate.

And the reason you have ghost data with removal after the changes is because Set use the hashcode to find the object to be removed. Since now you have 2 items with same hashcode, Set only removed 1 of them because it never expected 2 of them.
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Wirianto Djunaidi:
... is because Set use the hashcode to find the object to be removed.


HashSet uses the hashcode to find the object to be removed. Other Set implementations may work differently.
 
Yaroslav Ashurin
Greenhorn
Posts: 22
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I tried HashSet, TreeSet and LinkedHashSet- all of them lead to the same result: ghost entry after one at a time removal. Only iteration order changes from implementation to implementation. Literally, after removal System.out.print(set) brings {}, nothing in the brakets, and set.size() is allways 1, not zero. Frankly, I'm still not getting it... If Set's behavor is not predictable, how I would give a correct answer at scjp exam if such a question appears?
Anyway, thank you all for helping me to understand.
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The correct answer would be - the behaviour of a Set is not specified in these circumstances.

Originally posted by Yaroslav Ashurin:
Only iteration order changes from implementation to implementation.


This is nothing to do with having duplicate elements. A Set iterator returns the elements in no particular order, unless the set is an instance of some class that provides a guarantee.
[ June 30, 2008: Message edited by: Joanne Neal ]
 
Yaroslav Ashurin
Greenhorn
Posts: 22
Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Done. Thanks.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic