我有字符串的比较器,它被转换为日期。当我将这个比较器传递给Collections.sort()方法时,我得到 java.lang.IllegalArgumentException:比较方法违反了它的一般合约!。
我已经阅读了一些关于此例外的文章,但我并不清楚为什么会出现此异常。有什么想法吗?
private SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm");
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
if (o1 == null && o2 == null) {
return 0;
}
if (o1 == null) {
return 1;
}
if (o2 == null) {
return -1;
}
try {
Date first = sdf.parse(o1);
Date second = sdf.parse(o2);
return first.compareTo(second);
} catch (Exception ignored) {
return 0;
}
}
};
答案 0 :(得分:4)
如果抛出异常,则返回0.这意味着无论何时无法解析任何参数,两者都被视为相等。想想这个例子:
a = "01/01/2015"
b = "01/01/2016"
c = "xxx"
然后你得到
comparator.compare(a,c) = 0
comparator.compare(b,c) = 0
但
comparator.compare(a,b) != 0
解决方案:尝试单独解析每个字符串,并在异常时使用null
,如下所示:
private SimpleDateFormat sdf = new SimpleDateFormat(“dd / MM / yyyy HH:mm”);
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
Date first;
try {
first = sdf.parse(o1);
} catch (Exception ignored) {
first = null;
}
Date second;
try {
second = sdf.parse(o2);
} catch (Exception ignored) {
second = null;
}
if (first == second) {
return 0;
}
if (first == null) {
return 1;
}
if (second == null) {
return -1;
}
return first.compareTo(second);
}
};
答案 1 :(得分:2)
问题出在您的try catch
区块中。
即使其中一个日期不可解析,您也会返回0
(这意味着对象相等)。
现在让我们采取这种情况。
str1 = "invalid";
str2 = "10/10/2015"; //Consider this to be valid format.
str3 = "12/10/2015";
现在,让我们来看看比较,
0
(表示相等)0
(表示相等)这意味着,当您比较 str2 和 str3 时,应该是equal
。 (A=B
和A=C
表示B=C
)。
但是当它比较时,它会返回一个负数。因此例外。
答案 2 :(得分:1)
尼斯。你的问题实际上并不那么难......想象一下,你有三个弦乐......
Date 1 = correct date string for "Today"
Date 2 = correct date string for "Tomorrow"
Date 3 = XYZ (an non-correct date String that will throw an exception when parsed)
Date 1 < Date 2, obviously.
Date 2 > Date 1, also obvious, works fine
但现在是魔术/问题:
Date 3 == Date 1 - because of your exception handling
和
Date 3 == Date 2 - also because of that (for both you will return 0).
所以有一个与1和2都是EQUAL的Date,但是1和2不相等。
问问自己,你会在你的清单中将日期3放在哪里?它必须与日期1处于相同的“位置”(因为它与== 0比较)并且与日期2处于相同的“位置”(再次,它与== 0比较)。但是日期1和日期2不在同一位置。这是不可能的,因此你得到的“比较方法违反了它的一般合同!”。异常。
答案 3 :(得分:1)
您的字符串集可能有不可解决的日期。这导致在没有意义的情况下返回0。
String a = "badString";
String b = "20/12/2012 12:13";
String c = "20/12/2015 13:14";
b小于c且c大于b。因此,b和c不相等。但是你的函数说它们都等于String a!这没有任何意义,Collections.sort
无法正确排序。
b需要在c之前,c需要在b之后,但是需要在b AND c旁边。
处理比较器的更好方法是首先过滤字符串列表,这样您才能比较有效日期。然后,您的函数可以抛出一个关于仍然无法解析日期的RuntimeException。
答案 4 :(得分:0)
java.util.Arrays.sort和(间接)java.util.Collections.sort使用的排序算法已被替换。如果新的排序实现检测到违反Comparable合同的Comparable,则可能抛出IllegalArgumentException。以前的实现默默地忽略了这种情况。如果需要以前的行为,则可以使用新的系统属性java.util.Arrays.useLegacyMergeSort来恢复先前的mergesort行为