Java TreeSet: delete and contains () not working

I added some simple objects to the TreeSet, but when I call the TreeSet methods remove () and contains (), they do not work. However, when I iterate over the set, the object is printed. Employee objects must be added to the set, while the uniqueness of the objects is based on the property of the object name. The Id property is a value that must be sorted, but which is not unique.

public class Employee { private String name; private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } // Two objects are considered equal if their names are equal @Override public boolean equals(Object o) { if (o == null) return false; if (this == o) return true; if (o.getClass() == this.getClass()) { Employee p = ( Employee) o; if (p.getName() != null && this.getName() != null) return this.getName().equals(p.getName()); else return false; } else { return false; } } } //******************************************************* public class EmployeeComp implements Comparator<Employee> { // Sort Ids, but allow duplicates, hence this function is never returning 0 @Override public int compare(Employee p1, Employee p2) { int re = 0; boolean scoreLt = (p1.getId() > p2.getId()); boolean scoreGt = (p1.getId() < p2.getId()); if(scoreLt) re = -1; if(scoreGt) re = 1; else re = -1; return re; } } //******************************************************* // Collection shall store unique names with ordered values like: // Alex, 923 // Toni, 728 // Eddi, 232 // Peter, 232 // Eddi, 156 *** not allowed import java.util.TreeSet; public class Main { private static EmployeeComp comp = new EmployeeComp(); private static TreeSet<Employee> employees = new TreeSet<Employee>(comp); public static void main(String[] args) { Employee p1 = new Employee(); p1.setName("Eddi"); p1.setId(232); Employee p2 = new Employee(); p2.setName("Toni"); p2.setId(728); Employee p3 = new Employee(); p3.setName("Peter"); p3.setId(232); Employee p4 = new Employee(); p4.setName("Alex"); p4.setId(923); employees.add(p1); employees.add(p2); employees.add(p3); employees.add(p4); // Here, contains() and remove() should check the object address // and not perform their actions based on compareTo } } 
+6
source share
2 answers

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

+21
source

Your problem is conceptual.

If you want a sorted collection of unique objects: TreeSet
If you want the sorted collection to have different objects, then for sorting purposes there may be the same comparison value: PriorityQueue

By the way, the methods in PriorityList are more suitable for the usual needs of the second case than those used in the TreeSet. I used to think of it as the disadvantages of TreeSet. For example, to transfer the first item from a collection.

Hope that helps :-)

+3
source

Source: https://habr.com/ru/post/946717/


All Articles