比较方法在对文件进行排序时违反了其一般契约。

5
我知道有很多类似异常的问题,而且我已经找到了解决方法,但我的问题是,在不同的项目中相同的代码不会抛出异常,而这个项目会。两个项目都使用相同版本的Java和其他库。
基本上,我有一个小函数,从目录中检索文件列表,按时间戳排序,然后返回绝对文件名列表:
public static List<String> getFiles(String dir) {

    List<String> fileList = new ArrayList<String>();
    File[] files = new File(dir).listFiles();

    // Sort files by the date of their creation (last modification)
    Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);

    for (File f : files) {
        fileList.add(f.getAbsolutePath());
    }
    return fileList;

}

基本上,这段代码在一个项目中按预期执行,而在另一个项目中会抛出IllegalArgumentException: Comparison method violates its general contract!

我知道自从1.7版本以来,TimSort是Java的默认排序方法之一,其中解决方案之一是使用强制使用传统的MergeSort属性。我没有选择这条路...相反,我像这里建议的那样“缓存”文件及其时间戳:

public static List<String> getFiles(String dir) {

    List<String> fileList = new ArrayList<String>();
    File[] files = new File(dir).listFiles();

    FileLastModifiedPair[] pairs = new FileLastModifiedPair[files.length];
    for (int i = 0; i < files.length; i++) {
        pairs[i] = new FileLastModifiedPair(files[i]);
    }

    // Sort files by the date of their creation (last modification)
    Arrays.sort(pairs);

    // Take the sorted pairs and extract only the file part, discarding the timestamp
    for (FileLastModifiedPair pair : pairs) {
        fileList.add(pair.f.getAbsolutePath());
    }
    return fileList;
}

现在有多线程的问题,让我解释一下我的代码是做什么的:我有一个任务调度器,使用固定延迟调用方法getFiles(String),然后处理每个文件。
private Thread handleFiles () {
    return new Thread() {
        public void run() {

            List<String> files = getFiles("/home/user/files/");
            if (files.isEmpty()) {
                return;
            }

            for (String file : files) {
                try {
                    // handle file...
                } catch (Exception e) {
                    // log error...
                } finally {
                    // delete file...
                }

            }

        }
    };
}

当应用程序启动时,将调用此代码:

    Date startOfTomorrow = DateTime.now()
            .withTimeAtStartOfDay()
            .plusDays(1)
            .toDate();

    scheduler.scheduleWithFixedDelay(
            handleFiles(),
            startOfTomorrow,
            DELAY_IN_MILLIS);

基本上这是我的两个项目处理文件的方式。我的问题是:为什么第一个 getFiles(String) 方法在一个项目中起作用而在另一个项目中不起作用?如果它们使用了不同版本的Java或其他库(如Apache commons-io),我就会理解,但它们使用相同的版本。
编辑 #1:FileLastModifierPair.java:
public class FileLastModifiedPair implements Comparable<FileLastModifiedPair> {
    public File f;
    public long t;

    public FileLastModifiedPair(File file) {
        f = file;
        t = file.lastModified();
    }

    public int compareTo(FileLastModifiedPair that) {
        long result = this.t - that.t;

        if (result < 0) {
            return -1;
        } else if (result > 0) {
            return 1;
        } else {
            return 0;
        }
    }
}

3
请展示LastModifiedFileComparator类的代码。 - Codebender
@Codebender 这是Apache的commons-io类 - zkristic
2个回答

3

在某些情况下,文件的修改时间会在排序过程中发生变化,因此排序位置也会发生变化。今后可能会在另一个项目中出现类似情况。对我来说,通过缓存这些时间并创建目录快照的方法是正确的。


1
我不会在我的应用程序内或外更改文件(至少在所有文件都被排序并开始处理和删除它们之前不会这样做)。排序算法是否可能更改File.lastModified字段? - zkristic
有时候这个应用会出现错误。代码通常都能正常运行。你的回答可能会解释这个问题。 - undefined

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接