我正在排序一个对象数组。对象有很多字段,但我只关心其中一个。所以,我写了一个比较器:
Collections.sort(details, new Comparator<MyObj>() {
@Override
public int compare(MyObj d1, MyObj d2) {
if (d1.getDate() == null && d2.getDate() == null) {
return 0;
} else if (d1.getDate() == null) {
return -1;
} else if (d2.getDate() == null) {
return 1;
}
if (d1.getDate().before(d2.getDate())) return 1;
else if (d1.getDate().after(d2.getDate())) return -1;
else return 0;
}
});
从我的用例的角度来看,这个Comparator
完成了所有需要,即使我可能认为这种排序是非确定性的。但是,我想知道这是不好的代码。通过这个Comparator
,可以考虑两个非常不同的对象&#34;相同的&#34;即使它们是不相等的物体也要排序。我决定使用hashCode
作为决胜局,它出现了类似的内容:
Collections.sort(details, new Comparator<MyObj>() {
@Override
public int compare(MyObj d1, MyObj d2) {
if (d1.getDate() == null && d2.getDate() == null) {
return d1.hashCode();
} else if (d1.getDate() == null) {
return -1;
} else if (d2.getDate() == null) {
return 1;
}
if (d1.getDate().before(d2.getDate())) return 1;
else if (d1.getDate().after(d2.getDate())) return -1;
else return d1.hashCode() - d2.hashCode();
}
});
(我归来的可能是倒退,但这对这个问题并不重要)
这有必要吗?
修改 对于其他任何查看此问题的人,请考虑使用Google的订购API。上面的逻辑被替换为:
return Ordering.<Date> natural().reverse().nullsLast().compare(d1.getDate(), d2.getDate());
答案 0 :(得分:8)
通过这个比较器,可以考虑两个非常不同的对象&#34;相同&#34;即使它们是不相等的物体也要排序。
这真的不重要;对于两个对象比较是完全正常的,即使它们不是&#34;相等&#34;在任何其他意义上。 Collections.sort
是一个稳定的排序,意味着比较相等的对象按照它们的相同顺序出现;这相当于只使用&#34;输入中的索引&#34;作为决胜局。
(另外,您的新Comparator
实际上比原来的return d1.hashCode()
要严重得多。return d1.hashCode() - d2.hashCode()
特别荒谬,Collections.sort
会导致违反Integer.compare
的非传递性排序,由于溢出问题。除非两个整数都是非负的,哪个hashCodes不是,否则总是使用ParseQuery<ParseUser> query = ParseUser.getQuery();
query.findInBackground(new FindCallback<ParseUser>(){
public void done(List<ParseUser> userList, ParseException e) {
if (e == null) {
Log.d("score", "Retrieved " + userList.size() + " scores");
friends = new ArrayList<>();//<-- Initialize the String array
for (int i = 0; i < userList.size(); i++) {
friends.add(userList.get(i).getUsername());
}
aAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_dropdown_item_1line, friends);
friendChooser.setAdapter(aAdapter);
} else {
Log.d("score", "Error: " + e.getMessage());
}
}
});
来比较整数。)
答案 1 :(得分:2)
implement Comparable
。强烈建议(尽管不要求)自然排序与equals一致。 这是因为没有显式比较器的有序集(和有序映射)表现得很奇怪&#34;奇怪的是#34;当它们与自然排序与equals不一致的元素(或键)一起使用时。特别是,这样的有序集(或有序映射)违反了集合(或映射)的一般契约,它是用术语定义的。等于方法。
例如,如果添加两个键a和b使得(
!a.equals(b) && a.compareTo(b) == 0
)到不使用显式比较器的有序集,则第二个add操作返回false(并且有序集的大小确实如此)不要增加)因为a和b在排序集的视角中是等价的。
但是,您没有这样做,您可能会出于演示原因使用自定义Comparator
。由于此排序指标并非固有地附加到对象上,因此它并不重要。
顺便说一句,为什么不返回0而不是乱用hashCodes?然后,如果日期匹配,他们将保留原始订单,因为Collections.sort
是stable sort。我同意@LouisWasserman以这种方式使用hashCode可能会产生非常奇怪的后果,主要与整数溢出有关。考虑d1.hashCode()
为正且d2.hashCode()
为负数的情况,反之亦然。