A TreeSet inserts / deletes according to Comparable results, not .equals() / .hashCode() !
This means BTW that the objects in your Set do implement Comparable (if they didn’t, each time you tried and inserted a member, you would be greeted with a ClassCastException ).
To be more precise, TreeSet is an implementation of SortedSet .
If you need the .equals() / .hashCode() -compatible set, use, for example, a HashSet .
To illustrate, here's what happens with BigDecimal (published a few hours ago here ):
final BigDecimal one = new BigDecimal("1"); final BigDecimal oneDotZero = new BigDecimal("1.0"); final Set<BigDecimal> hashSet = new HashSet<>(); // BigDecimal implements Comparable of itself, so we can use that final Set<BigDecimal> treeSet = new TreeSet<>(); hashSet.add(one); hashSet.add(oneDotZero); // hashSet size is 2: one.equals(oneDotZero) == false treeSet.add(one); treeSet.add(oneDotZero); // treeSet size is... 1! one.compareTo(oneDotZero) == 0
To quote javadoc for Comparable , this means that BigDecimal .compareTo() "does not match .equals() ".
** EDIT ** Regarding OP:
- a
Collection that will not accept duplicate names; - sorted view of this
Collection , which will be sorted against the user ID.
As mentioned above, you cannot have one collection that does how . Decision:
- for the first, a
HashSet ; - for the second, a copy of this set in
ArrayList , then using Collections.sort() .
This means that .equals() and .hashCode() should act only on the name, while the custom Comparator will act on the id. Comparator has no choice but to be ordinary, as it is a comparator that is not associated with .equals() in any case.
Regarding the proposed code, problems arise.
First: Employee overrides .equals() , but not .hashCode() . Thus, Employee violates the .equals() contract (one part of which is that if two objects are equal, they must have the same hash code). Moreover, .hashCode() is crucial for a HashSet to work in general. Fix:
@Override public int hashCode() { return name == null ? 0 : name.hashCode(); } @Override public boolean equals(final Object obj) { if (obj == null) return false; if (this == obj) return false; if (!(obj instanceof Employee)) return false; final Employee other = (Employee) obj; return name == null ? other.name == null : name.equals(other.name); }
Secondly: the comparator is also broken as Employee , since it violates the Comparator contract (for any o1 and o2 , o1.compareTo(o2) == - o2.compareTo(o1) ). Fix:
public final class EmployeeComp implements Comparator<Employee> { @Override public int compare(final Employee o1, final Employee o2) { final int id1 = o1.getId(), id2 = o2.getId(); if (id1 == id2) return 0; return id1 > id2 ? 1 : -1; } }
Then, how to get a sorted copy of the set:
// "set" contains the unique employees final List<Employee> sorted = new ArrayList<Employee>(set); Collections.sort(list, new EmployeeComp());
DONE