我知道为了符合Java List<SelectListItem> userDdl = GetUserDropDown(userId, userName).ToSelectListItems(a => a.UserName, a => a.UserId.ToString(), a => a.UserId.ToString() == userIdFromDb).ToList();
的合同(以避免意外行为),任何提供的Collections
都应与equals保持一致。
假设我有这样的人:
Comparator
比较者将是
class Person {
private String name;
private String surname;
private int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() { return name; }
public String getSurname() { return surname; }
public int getAge() { return age; }
}
现在我想要一些排序的集合(class PersonComparator implements Comparator<Person> {
@Override
public int compareTo(Person p1, Person p2) {
// throws NPE's
return p1.getName().compareTo(p2.getName());
}
}
,TreeMap
,......无论如何),使用SortedSet
仅比较Comparator
的名称。
这个比较器会违反&#34;与equals&#34;合同。但是我不想覆盖Person
,因为在该计划的其他部分,两个姓名,年龄相同的人可能会有所不同(如现实生活中)。
我希望在所选集合中,该名称唯一标识一个人,即equals(Object o)
不能拥有&#34; John Doe&#34;和#34;约翰史密斯&#34; (一样的名字)。
就我所测试的Java Collections的当前实现而言,这很好。
我的问题是:你如何做到这一点&#34;正确&#34;,理想情况下没有违反任何合同?如果可能的话,我想避开第三方库,当然我不想自己实现数据结构只是为了摆脱合同。 我担心的是,我的代码可能会在未来的Java版本中破坏,因为它违反了合同。
答案 0 :(得分:3)
您遇到的问题是设置忽略重复项。如果你说两个Person
是相同的,它会将它们视为重复并删除其中一个。
return p1.getName().compareTo(p2.getName());
所以如果你有两个人叫#&#34; John&#34;作为名字,它们只会在TreeSet中出现一次。
你需要的是比较你在equals中所做的相同领域。
int cmp = p1.getName().compareTo(p2.getName());
if (cmp == 0)
cmp = p1.getSurname().compareTo(p2.getSurname());
if (cmp == 0)
cmp = Integer.compare(p1.getAge() - p2.getAge());
return cmp;
这样你只会考虑两个等于== true的人是重复的。
确保具有相同细节(但不同)的人不被视为重复的方法是添加唯一ID,计数器或UUID。
注意:合同不一定要保持一致,而对于BigDecimal,它并不完全一致,但在这种情况下,我没有看到你想要对待John Smith和John的充分理由Doe是同一个人。
答案 1 :(得分:1)
如果您使用的是Java 8,我建议您使用Comparator
中的实用程序方法,而不是自己编写。
例如:
SortedSet<Person> people = new TreeSet<>(Comparator.comparing(Person::getName));
将实现的所有复杂性留给内置方法。它还允许您利用各种可用方法来定义多个排序条件,处理空值等。因为这些方法是API的一部分,所以您可以确信您的代码在将来的版本中不会中断。