Comparison method violates its general contract! 问题
引言
今天下午正在摸鱼,这时候突然客户在群里反馈,说今天数据没有了,催我赶紧去看,于是我连上客户服务器,打开今天的项目日志,看到了下面的错误
Comparison method violates its general contract
问题原因
花了几分钟解决,记录一下
先看下之前的代码,功能就是获取指定目录下最近修改的文件名称,里面用到了Arrays.sort
排序
/** 读取特定目录下最新的文件名称
* @param filePath 文件路径
* @return String
*/
public static String getLatestFile(String filePath ) {
String latestFile = "";
// 获取最新改动的文件名
try {
File path = new File(filePath);
if (path.exists()) {
// 列出该目录下所有文件和文件夹
File[] files = path.listFiles();
if (null == files || files.length <= 0) {
return latestFile;
}
// 按照文件最后修改日期倒序排序
Arrays.sort(files, (file1, file2) -> {
Long result = file2.lastModified() - file1.lastModified();
//先将Long的差值算出,然后视该值是否会超越int的最大值,然后返回不同结果
return result>=Integer.MAX_VALUE?Integer.MAX_VALUE:result.intValue();
});
latestFile = files[0].getName();
}else{
log.error("the latest file path is not exist:"+filePath);
latestFile = "";
}
} catch (Exception e) {
log.info("getLatestFile error", e);
}
return latestFile;
}
这段代码乍一看功能可以实现,测试也没有问题,为什么报错?
在 JDK7 版本以上,Comparator
要满足自反性,传递性,对称性,不然 Arrays.sort
,Collections.sort
会报 IllegalArgumentException
异常。
- 自反性:x,y 的比较结果和 y,x 的比较结果相反,即
sgn(compare(x,y)) == -sgn(compare(y,x))
。 - 传递性:x > y,y > z,则 x > z,即
((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0
。 - 对称性:x=y,则 x,z 比较结果和 y,z 比较结果相同。即
compare(x,y)==0 implies that sgn(compare(x,z))==sgn(compare(y,z)) for all z
。
解决方案
方法1
强制 JVM 使用老旧的 MergeSort,而非新的 TimSort。
(1) 可以在代码层面上进行声明
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
(2) 也可以在 JVM 的启动参数中声明
-Djava.util.Arrays.useLegacyMergeSort=true
方法2
修改代码,使得比较器 Comparator
满足新算法自反性、传递性、对称性的要求,建议使用方法二
public static String getLatestFile(String filePath ) {
String latestFile = "";
// 获取最新改动的文件名
try {
File path = new File(filePath);
if (path.exists()) {
// 列出该目录下所有文件和文件夹
File[] files = path.listFiles();
if (null == files || files.length <= 0) {
return latestFile;
}
// LOG.info("Files in "+fileName+", files num="+files.length);
// 按照文件最后修改日期倒序排序
Arrays.sort(files, (file1, file2) -> {
Long f1 = file1.lastModified();
Long f2 = file2.lastModified();
// 这里改用 compareTo 方法
return f2.compareTo(f1);
//Long result = file2.lastModified() - file1.lastModified();
//先将Long的差值算出,然后视该值是否会超越int的最大值,然后返回不同结果
//return result>=Integer.MAX_VALUE?Integer.MAX_VALUE:result.intValue();
});
latestFile = files[0].getName();
}else{
log.error("the latest file path is not exist:"+filePath);
latestFile = "";
}
} catch (Exception e) {
log.info("getLatestFile error", e);
}
return latestFile;
}
compareTo 源码
public int compareTo(Long anotherLong) {
return compare(this.value, anotherLong.value);
}
public static int compare(long x, long y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
身体和灵魂都要在路上