This question already has an answer here:
I'm trying to sort my custom NewsAdapter
by a Date
property of the Articles_Map
object, and I've noticed that in cases with bigger data sets my app crashes with a java.lang.IllegalArgumentException: Comparison method violates its general contract!
error.
I'm not sure if that error happens because of an int
overflow, or if it is indeed related to the transitive property of the contract. And particularly for the latter, I don't know how to fix it, because as far as I understand I'm already handling the 3 possible outcomes (less than 0, 0, greater than 0).
public class NewsAdapter extends ArrayAdapter<Articles_Map> {
Context mContext;
public NewsAdapter(Context c, int resource) {
super(c, resource);
this.mContext = c;
}
protected void doAdd(Articles_Map another) {
super.add(another);
}
public void addAll(List<Articles_Map> others) {
for (Articles_Map a : others) {
this.doAdd(a);
}
this.sort(byPublishedAtComparator);
}
private static final Comparator<Articles_Map> byPublishedAtComparator =
new Comparator<Articles_Map>() {
@Override
public int compare(Articles_Map o1, Articles_Map o2) {
// needs further testing in case of nulls
if (o1.publishedAt == null || o2.publishedAt == null) {
return 0;
}
return o1.publishedAt.compareTo(o2.publishedAt);
}
};
}
Convert this variable into a class like that:
And instead
this.sort(byPublishedAtComparator);
, you have to callYour
Comparator
violates the transitivity requirement ifpublishedAt
isnull
.Say you have three instances of
Articles_Map
:publishedAt
publishedAt
==null
publishedtAt
that is greater thana
s valueNow if you call your comparator with
a
andb
or withb
andc
, the comparator returns0
for both calls.To satisfy the transitivity rule, your comparator must also return
0
if it is called witha
andc
. But since the fieldpublishedAt
is notnull
on both objects, it will return a value less than0
if prepared like described.To fix this, your comparator must not return
0
if only one ofo1.publishedAt
ando2.publishedAt
isnull
.For example:
Consider the following three instances:
That violates the contract ... and doesn't make sense. (If A1 is equal to A2 and A2 is equal to A3, then A1 should be equal to A3!)
The solution would be to treat
null
as being equivalent to a specific numeric value; e.g.Integer.MIN_VALUE
ifpublished_at
is anint
.