file - android 中的文件排序列表抛出“比较方法违反了它的一般合同!”
问题描述
它发生在我的 Android 应用程序上,这是堆栈跟踪:
Caused by java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:864)
at java.util.TimSort.mergeAt(TimSort.java:481)
at java.util.TimSort.mergeForceCollapse(TimSort.java:422)
at java.util.TimSort.sort(TimSort.java:219)
at java.util.TimSort.sort(TimSort.java:169)
at java.util.Arrays.sort(Arrays.java:2023)
at java.util.Collections.sort(Collections.java:1883)
这是我的排序逻辑:
private static void sortFiles(List<File> listFiles, int sortDirection) {
try {
if (sortDirection == sortLatestFirst) {
Collections.sort(listFiles, new LatestFirstComparator());
...
这是比较器:
class LatestFirstComparator implements Comparator<File> {
@Override
public int compare(File f1, File f2) {
return Long.compare(f2.lastModified(), f1.lastModified());
}
}
我找到了相关的问题和其他解决方案,但没有一个能解决我的问题。此外,这不是一致的行为,而是仅发生在某些应用程序用户身上。
解决方案
正如其他人所说,问题在于最后修改的时间戳的值在排序操作期间可能会发生变化。为了可靠地排序,您必须在排序操作期间缓存值:
private static void sortFiles(List<File> listFiles, int sortDirection) {
if(listFiles.isEmpty()) return;
Map<File,Long> cache = new HashMap<>();
Comparator<File> byTime
= Comparator.comparing(f -> cache.computeIfAbsent(f, File::lastModified));
if(sortDirection == sortLatestFirst) byTime = byTime.reversed();
listFiles.sort(byTime);
}
我假设您无论如何都使用更改通知机制来决定何时重新加载文件列表,因此排序操作不需要处理它。
如果要支持不支持 Java 8 功能的 API 级别,则必须使用更详细的变体
private static void sortFiles(List<File> listFiles, int sortDirection) {
if(listFiles.isEmpty()) return;
final Map<File,Long> cache = new HashMap<File,Long>();
Comparator<File> byTime = new Comparator<File>() {
@Override
public int compare(File f1, File f2) {
Long t1 = cache.get(f1), t2 = cache.get(f2);
if(t1 == null) cache.put(f1, t1 = f1.lastModified());
if(t2 == null) cache.put(f2, t2 = f2.lastModified());
return t1.compareTo(t2);
}
};
if(sortDirection == sortLatestFirst) byTime = Collections.reverseOrder(byTime);
Collections.sort(listFiles, byTime);
}
推荐阅读
- java - 用 mockito 监视 lambda
- python - 如果字典列表中有重复记录,如何添加值?
- wordpress - 需要联系表格 7 下拉力吗?
- google-analytics - GTM 和跨域跟踪:我是否需要在所有在第二个域上触发的标签中设置它?
- node.js - Node.js - “node”命令有效,但通过另一个框架时无效
- string - 如何从字符串中删除尾随“\r\n”
- c# - 使用 asp.net mvc 使用 stackexchange Api
- java - Spring Annotation 驱动的配置 - 无法解析匹配的构造函数
- c - 两个大数 char 类型的最高有效数字之和
- vue.js - Vue.js 单元测试确保组件在挂载后稳定