为什么我的比较方法有时会抛出 IllegalArgumentException?

2023-11-22

我遇到这个问题已经有一段时间了,搜索了很多 StackOverflow 问题但无法解决我的问题。

我之前也问过类似的问题并得到了使用建议,

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

它没有解决我的问题。我在任何测试设备上都从未遇到过此异常,但我的一些用户定期报告此情况。我真的不知道如何解决它。

例外情况

这是我遇到的例外,

java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:743)
at java.util.TimSort.mergeAt(TimSort.java:479)
at java.util.TimSort.mergeCollapse(TimSort.java:404)
at java.util.TimSort.sort(TimSort.java:210)
at java.util.TimSort.sort(TimSort.java:169)
at java.util.Arrays.sort(Arrays.java:2023)
at java.util.Collections.sort(Collections.java:1883)

或者有时这样,

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.mergeCollapse(TimSort.java:406)
at java.util.TimSort.sort(TimSort.java:210)
at java.util.TimSort.sort(TimSort.java:169)
at java.util.Arrays.sort(Arrays.java:2010)
at java.util.Collections.sort(Collections.java:1883)

我做了什么

enum FileItemComparator implements Comparator<FileItem> {

    //Using ENUM
    NAME_SORT {
        public int compare(FileItem o1, FileItem o2) {

            int result = 0;
            if (o1 != null && o2 != null) {

                String n1 = o1.getFileName();
                String n2 = o2.getFileName();

                if (n1 != null && n2 != null)
                    result = n1.compareTo(n2);
            }

            return result;
        }
    },
    DATE_SORT {
        public int compare(FileItem o1, FileItem o2) {

            int result = 0;
            if (o1 != null && o2 != null) {

                String d1 = o1.getFileDate();
                String d2 = o2.getFileDate();

                if (d1 != null && d2 != null) {

                    Long l1 = Long.valueOf(d1);
                    Long l2 = Long.valueOf(d2);

                    if (l1 != null && l2 != null) {
                        result = l1.compareTo(l2);
                    }
                }

            }

            return result;
        }
    },
    SIZE_SORT {
        public int compare(FileItem o1, FileItem o2) {

            int result = 0;
            if (o1 != null && o2 != null) {

                File f1 = o1.getItem();
                File f2 = o2.getItem();

                if (f1 != null && f2 != null) {

                    result = Long.valueOf(f1.length()).compareTo(Long.valueOf(f2.length()));
                }
            }

            return result;
        }
    };

    public static Comparator<FileItem> descending(final Comparator<FileItem> other) {

        return new Comparator<FileItem>() {
            public int compare(FileItem o1, FileItem o2) {
                return -1 * other.compare(o1, o2);
            }
        };
    }

    public static Comparator<FileItem> getComparator(final FileItemComparator... multipleOptions) {
        return new Comparator<FileItem>() {
            public int compare(FileItem o1, FileItem o2) {
                for (FileItemComparator option : multipleOptions) {
                    int result = option.compare(o1, o2);
                    if (result != 0) {
                        return result;
                    }
                }
                return 0;
            }
        };
    }
}

我就是这样排序的

Collections.sort(dirs, FileItemComparator.getComparator(FileItemComparator.NAME_SORT));

问题

我确信具有传递依赖性的比较方法有问题。我已经尝试了很多,但似乎无法修复它。事实上,我在任何测试设备上都没有遇到过这个问题,但我的用户不断报告这个问题。

我希望这里的任何人都能够抓住这个问题并帮助我一劳永逸地解决它。

更新代码(感谢@Eran)

我认为最好通过发布完整的更新代码来帮助其他人。这将帮助很多面临同样问题的人。

enum FileItemComparator implements Comparator<FileItem> {

    //Using ENUM
    NAME_SORT {
        public int compare(FileItem o1, FileItem o2) {

            if (o1 == null) {
                if (o2 == null) {
                    return 0;
                } else {
                    return 1; // this will put null in the end
                }
            } else if (o2 == null) {
                return -1;
            }

            String n1 = o1.getFileName();
            String n2 = o2.getFileName();

            if (n1 == null) {
                if (n2 == null) {
                    return 0;
                } else {
                    return 1; // this will put null names after non null names
                }
            } else if (n2 == null) {
                return -1;
            }
            return n1.compareTo(n2);
        }
    },
    DATE_SORT {
        public int compare(FileItem o1, FileItem o2) {

            if (o1 == null) {
                if (o2 == null) {
                    return 0;
                } else {
                    return 1; // this will put null in the end
                }
            } else if (o2 == null) {
                return -1;
            }

            String d1 = o1.getFileDate();
            String d2 = o2.getFileDate();

            if (d1 == null) {
                if (d2 == null) {
                    return 0;
                } else {
                    return 1; // this will put null names after non null names
                }
            } else if (d2 == null) {
                return -1;
            }

            Long l1 = Long.valueOf(d1);
            Long l2 = Long.valueOf(d2);

            if (l1 == null) {
                if (l2 == null) {
                    return 0;
                } else {
                    return 1; // this will put null names after non null names
                }
            } else if (l2 == null) {
                return -1;
            }

            return l1.compareTo(l2);
        }
    },
    SIZE_SORT {
        public int compare(FileItem o1, FileItem o2) {

            if (o1 == null) {
                if (o2 == null) {
                    return 0;
                } else {
                    return 1; // this will put null in the end
                }
            } else if (o2 == null) {
                return -1;
            }

            File f1 = o1.getItem();
            File f2 = o2.getItem();

            if (f1 == null) {
                if (f2 == null) {
                    return 0;
                } else {
                    return 1; // this will put null in the end
                }
            } else if (f2 == null) {
                return -1;
            }

            Long l1 = Long.valueOf(f1.length());
            Long l2 = Long.valueOf(f2.length());

            if (l1 == null) {
                if (l2 == null) {
                    return 0;
                } else {
                    return 1; // this will put null names after non null names
                }
            } else if (l2 == null) {
                return -1;
            }

            return l1.compareTo(l2);
        }
    };

    public static Comparator<FileItem> descending(final Comparator<FileItem> other) {

        return new Comparator<FileItem>() {
            public int compare(FileItem o1, FileItem o2) {
                return -1 * other.compare(o1, o2);
            }
        };
    }

    public static Comparator<FileItem> getComparator(final FileItemComparator... multipleOptions) {
        return new Comparator<FileItem>() {
            public int compare(FileItem o1, FileItem o2) {
                for (FileItemComparator option : multipleOptions) {
                    int result = option.compare(o1, o2);
                    if (result != 0) {
                        return result;
                    }
                }
                return 0;
            }
        };
    }
}

让我们看看你的第一个比较方法:

    public int compare(FileItem o1, FileItem o2) {

        int result = 0;
        if (o1 != null && o2 != null) {

            String n1 = o1.getFileName();
            String n2 = o2.getFileName();

            if (n1 != null && n2 != null)
                result = n1.compareTo(n2);
        }

        return result;
    }

假设您正在比较两个 FileItem(我们称它们为 o1 和 o2),一个带有文件名,另一个没有(即空文件名)。你的方法将返回 0。

现在,如果将 o2 与文件名不为空的另一个 FileItem (o3) 进行比较,则会再次返回 0。

但如果比较 o1 和 o3,由于它们都有非空文件名,因此比较返回 -1 或 1(假设文件名不同)。

因此,您的比较是不一致的,因为它不具有传递性。

如果一个元素缺少比较所需的属性,而另一个元素没有,则不应返回 0。您应该决定是否返回 1 或 -1(例如,取决于名称为 null 的 FileItems 是否应排序在或在具有非空名称的 FileItems 之后)。

例如 :

public int compare(FileItem o1, FileItem o2) 
{
    if (o1 == null) {
        if (o2 == null) {
            return 0;
        } else {
            return 1; // this will put null in the end
        }
    } else if (o2 == null) {
        return -1;
    }
    String n1 = o1.getFileName();
    String n2 = o2.getFileName();
    if (n1 == null) {
        if (n2 == null) {
            return 0;
        } else {
            return 1; // this will put null names after non null names 
        }
    } else if (n2 == null) {
        return -1;
    }
    return n1.compareTo(n2);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么我的比较方法有时会抛出 IllegalArgumentException? 的相关文章

随机推荐

  • 在 Windows 7 计算机上编写/编译的 .NET 4 程序无法在 XP 上运行

    我有一个在 Windows 7 Ultimate 计算机上的 Visual Studio 2010 中使用 C NET 4 0 编写的应用程序 该应用程序在 Vista 和其他 Windows 7 计算机上运行良好 但每当运行 Window
  • Spring Security 5.2 密码流程

    我正在尝试使用最新版本的 Spring Security 5 2 中的密码流对用户进行身份验证 The 文档似乎建议怎么做 Bean public OAuth2AuthorizedClientManager passwordFlowAuth
  • 如何在不使用时间戳列的 INT96 格式的情况下将 Spark 数据帧保存到镶木地板?

    我有一个 Spark 数据框 我想将其保存为 parquet 然后使用 parquet avro 库加载它 我的数据帧中有一个时间戳列 它被转换为 parquet 中的 INT96 时间戳列 然而镶木地板阿夫罗不支持INT96格式并抛出 有
  • @types/node 安装的打字稿版本无法找到模块“child_process”

    我找到了打字稿版本node不幸的是它无法找到 子进程 节点包中的模块 我的控制台中的错误消息正是找不到模块 错误 无法解析 child process 当我浏览一些博客时 他们建议在您的tsconfig json file typeRoot
  • 抓取无限滚动的动态电子商务页面

    我在用着rvest在 R 中进行一些抓取 我了解一些 HTML 和 CSS 我想获取 URI 的每种产品的价格 http www linio com co tecnologia celulares telefonia gps 当您在页面上向
  • 没有ConfigureAwait(false)的await在不同的线程上继续

    我有一个 WinForms 应用程序 并且有一些需要在 UI 线程上运行的代码 然而 后面的代码await在不同的线程上运行 protected override async void OnHandleCreated EventArgs e
  • 如何使用 blazor 标记使用本地文化格式化日期

    我在 Blazor 应用程序中使用该标签 但是我如何使用我自己的文化来格式化日期
  • Python Sphinx autodoc 未在 readthedocs 上呈现

    我有一个托管在 Github 上的 Python 包 名为spike2py 我已经使用 Sphinx 和 rst 文件准备了我的文档 这些文件托管在 GitHub 上here 我能够成功运行make html本地并获得所需的输出 也就是说
  • DB设计是否使用子类型?

    我正在设计的数据库有3个主要表 BOOKS ARTICLES NOTES 每本书或一篇文章可以有多个笔记 我最初的设计就是这样 这意味着书籍笔记和文章笔记都放在 笔记 表中 以下是用于NOTES table note id note typ
  • 使用 JacksonMapper 反序列化 Java 8 LocalDateTime

    我已经阅读了几个关于 SO 之间的序列化和反序列化的问题及其答案java time LocalDateTime和 JSON 属性 但我似乎无法让它工作 我已成功配置我的 Spring Boot 应用程序以我想要的格式返回日期 YYY MM
  • 使用 Express 路由处理请求参数中的斜杠字符

    我目前正在使用 Express 开发一个 URL 缩短器应用程序 我希望用户能够输入这样的 URL https www exampleurlshortener com new https www google com 问题是 每当我尝试使用
  • 如何在传输级别压缩来自 WCF .NET 的 HTTP 请求?

    我已经设法在 ASP NET 上启用入站 HTTP 压缩 即HTTP的压缩requests 不仅仅是回复 但我现在在客户端 C NET 4 0 应用程序 苦苦挣扎 我想 添加 HTTP 标头Content Encoding gzip 使用
  • UITableView -headerViewForSection 返回(空)

    我有一个UITableView有 2 个部分 各有各的headerView 我创建了一个自定义headerView通过 viewForHeaderInSection method 后来 我打算稍微修改一下 所以我需要使用viewForHea
  • 大型 JPEG/PNG 图像序列循环

    我一直在从事有关遥感图像处理和图像序列循环的项目 每个生成的图像 JPEG 或 PNG 格式 大约有 8000 4000 像素 我们的用户通常希望根据感兴趣的区域一次循环图像序列 超过 50 张图像 因此 我必须根据用户的可视化客户端大小从
  • 具有 .Net Core 3.0 不记名令牌授权的 Swagger UI

    我正在尝试将授权标头添加到 SwaggerUI api 测试中 下面是我的 Startup cs public void ConfigureServices IServiceCollection services services AddC
  • PHP 会话默认超时[重复]

    这个问题在这里已经有答案了 PHP 会话默认超时吗 即 如果我没有任何编码 用户在一段时间不活动后最终会 注销 吗 这取决于服务器配置或相关指令会话 gc maxlifetime in php ini 通常 默认值为 24 分钟 1440
  • Kafka 多分区排序

    我知道在 Kafka 中不可能对多个分区进行排序 并且分区排序仅保证组内的单个消费者 对于单个分区 然而 使用 Kafka Streams 0 10 现在可以实现这一目标吗 如果我们使用时间戳功能 以便每个分区中的每条消息都保持顺序 那么在
  • htaccess 缓存不起作用

    我将以下内容输入到 htacces 文件中 以便开始缓存 Web 内容 根据 Google Page Speed 和 Yslow 页面仍未被缓存 模块有错吗 或者是应用程序没有正确显示数据 站点在服务器上的 Apache 2 0 上运行 h
  • .htaccess 重定向不适用于 Angular 4

    我知道很多人问这个问题 但我查看了所有答案 但没有任何效果 我确信问题是我需要创建一个 htaccess 文件并将其添加到我的 dist 中 因为这就是 ISP 控制台指南所说的要做的事情 我正在使用 Angular cli 和构建命令 n
  • 为什么我的比较方法有时会抛出 IllegalArgumentException?

    我遇到这个问题已经有一段时间了 搜索了很多 StackOverflow 问题但无法解决我的问题 我之前也问过类似的问题并得到了使用建议 System setProperty java util Arrays useLegacyMergeSo