Comparison method violates its general contract! 问题

2022-09-19 14:56:48 浏览数 (1)

引言

今天下午正在摸鱼,这时候突然客户在群里反馈,说今天数据没有了,催我赶紧去看,于是我连上客户服务器,打开今天的项目日志,看到了下面的错误 Comparison method violates its general contract

问题原因

花了几分钟解决,记录一下

先看下之前的代码,功能就是获取指定目录下最近修改的文件名称,里面用到了Arrays.sort 排序

代码语言:javascript复制
/** 读取特定目录下最新的文件名称
 * @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.sortCollections.sort 会报 IllegalArgumentException 异常。

  1. 自反性:x,y 的比较结果和 y,x 的比较结果相反,即 sgn(compare(x,y)) == -sgn(compare(y,x))
  2. 传递性:x > y,y > z,则 x > z,即 ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0
  3. 对称性: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) 可以在代码层面上进行声明

代码语言:javascript复制
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

(2) 也可以在 JVM 的启动参数中声明

代码语言:javascript复制
-Djava.util.Arrays.useLegacyMergeSort=true

方法2

修改代码,使得比较器 Comparator 满足新算法自反性、传递性、对称性的要求,建议使用方法二

代码语言:javascript复制
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 源码

代码语言:javascript复制
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);
}
jvm

0 人点赞