简体   繁体   English

使用Comparator时从TreeSet丢失数据

[英]Data lost from TreeSet when using Comparator

I have the following code which will sort the Employees's based on their experience. 我有以下代码,根据他们的经验对Employees's排序。

I am adding 2 employees with different name and same experience . 我正在增加2名不同nameexperience员工。 I am expecting that at the end set will have 2 employees, but I am getting only one. 我期待在最后一set将有2名员工,但我只有一名。

I have also overridden equals and hashcode , Can any one tell me why I am getting only one employee in the set. 我也覆盖了equalshashcode ,任何人都可以告诉我为什么我只能在集合中获得一名员工。

Test Class 测试类

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.junit.Test;

public class SetWithComparator {


    @Test
    public void testComparatorWithSet() {

        Comparator<Employee> comparator =
                (emp1, emp2) -> emp1.getYearOFExp().compareTo(emp2.getYearOFExp());

        Set<Employee> empSet = new TreeSet<>(comparator);

        Employee e1 = new Employee();
        e1.setName("Employee-1");
        e1.setYearOFExp(12f);

        Employee e2 = new Employee();
        e2.setName("Employee-2");
        e2.setYearOFExp(12f);

        empSet.add(e1);
        empSet.add(e2);

    }

}

Model Class 模型类

class Employee {


    private String name;
    private Float yearOFExp;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getYearOFExp() {
        return yearOFExp;
    }

    public void setYearOFExp(Float yearOFExp) {
        this.yearOFExp = yearOFExp;
    }

    @Override
    public boolean equals(Object obj) {

        if (obj instanceof Employee) {

            Employee e = (Employee) obj;
            return new EqualsBuilder().append(name, e.getName()).isEquals();
        } else {
            return false;
        }

    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(name).toHashCode();
    }

}

Because the comparator is not consistent with your equals method. 因为比较器与你的equals方法不一致。 Please check the documentation of Comparator . 请查看比较器的文档。

The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S. 当且仅当c.compare(e1,e2)== 0具有与每个e1的e1.equals(e2)相同的布尔值时,比较器c对一组元素S施加的排序被称为与等于一致。和S中的e2

Caution should be exercised when using a comparator capable of imposing an ordering inconsistent with equals to order a sorted set (or sorted map). 当使用能够强加与equals不一致的排序的比较器来排序有序集(或有序映射)时,应该谨慎行事。 Suppose a sorted set (or sorted map) with an explicit comparator c is used with elements (or keys) drawn from a set S. If the ordering imposed by c on S is inconsistent with equals, the sorted set (or sorted map) will behave "strangely." 假设带有显式比较器c的有序集(或有序映射)与从集合S中绘制的元素(或键)一起使用。如果由S对S施加的排序与equals不一致,则排序集(或有序映射)将表现得“奇怪”。 In particular the sorted set (or sorted map) will violate the general contract for set (or map), which is defined in terms of equals. 特别是有序集(或有序映射)将违反集合(或映射)的一般契约,其以等于的方式定义。

The exact behavior that you experience is hinted in the docs of Comparable (although you use comparator): 您可以在Comparable的文档中暗示您遇到的确切行为(尽管您使用比较器):

For example, if one adds two keys a and b such that (!a.equals(b) && a.compareTo(b) == 0) to a sorted set that does not use an explicit comparator, the second add operation returns false (and the size of the sorted set does not increase) because a and b are equivalent from the sorted set's perspective. 例如,如果添加两个键a和b使得(!a.equals(b)&& a.compareTo(b)== 0)到不使用显式比较器的有序集,则第二个add操作返回false (并且有序集的大小不会增加)因为a和b从排序集的角度来看是等价的。

In your case: comparator.compare(e1, e2) is 0 , e1.equals(e2) is false . 在您的情况下: comparator.compare(e1, e2)0e1.equals(e2)false

For a SortedSet , the Comparator determines what elements are the same and it won't contain duplicates. 对于SortedSetComparator确定哪些元素相同,并且不包含重复项。 If you don't want to consider all employees with the same experience to be the same, you have to add a secondary ordering: 如果您不想将具有相同体验的所有员工视为相同,则必须添加二级订购:

Comparator<Employee> comparator = Comparator.comparing(Employee::getYearOFExp)
                                            .thenComparing(Employee::getName);

Note that you have to include all properties that make up the identity of an employee. 请注意,您必须包含构成员工身份的所有属性。 In your example, there is only the name, however, in real life scenarios you would have more. 在您的示例中,只有名称,但在现实生活中,您可以拥有更多。 On the other hand, if you have an ID, that determines the identity, you don't need to check other properties and, in fact, shouldn't , as most properties, including the name, can change. 另一方面,如果您有一个确定身份的ID,则不需要检查其他属性,事实上, 不应该这样 ,因为大多数属性(包括名称)都可以更改。 This also applies to the implementation of equals and hashCode . 这也适用于equalshashCode的实现。

In order to warn about false assumptions about what can be assumed to be granted, gender changes are a real life fact and even birthdays may turn out to be false and need a correction. 为了警告关于可以假设给予什么的错误假设,性别变化是一个真实的生活事实,甚至生日可能会变成虚假的,需要纠正。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM