当前位置: 首页 > 知识库问答 >
问题:

为什么我会得到这个异常Java . lang . illegalargumentexception:比较方法违反了它的通用契约

莫宝
2023-03-14

我有这个代码。getCreatedAt 是一个长整型,表示记录的时间戳。

Collections.sort(records, new Comparator<Record>() {
    @Override
    public int compare(Record record1, Record record2) {
        return (int) (record2.getCreatedAt() - record1.getCreatedAt());
    }
});

当我使用足够的数据(列表中大约有 200 个项目)运行它时。我开始遇到这个异常

java.lang.IllegalArgumentException:比较方法违反了它的一般约定!

当然,当我编写此代码时,我意识到理论上它可以具有整数溢出,但感觉不太可能,因为时间戳将相隔几天或几周,而不是几十年。

我现在已经通过总是返回1、-1或0来修复这个问题,但是我很好奇为什么这个异常会首先发生。

共有1个答案

齐英朗
2023-03-14

我假设时间戳是s,因为否则您将不需要(int)转换。

那样的话,就是因为溢出了。< code>int可以保存从-2147483648到2147483647的值。如果减法结果大于或小于该值,那么将结果转换为< code>int会导致其回绕。

例如,如果 record2.getCreatedAt() 是 2147483648,而 record1.getCreatedAt() 是 0,那么你的函数返回 -2147483648,这表明 record1 更大(显然是错误的!)。

现在,这本身没关系,这意味着你会按错误的顺序得到东西,但它不应该崩溃,对吧?事实上,它会导致车祸。

让我们调用记录为2147483648的记录A和记录为0的记录C。如果中间有另一个记录B,时间戳为100000000,那么您的函数表示C在A之后,A在B之后,B在C之后。这是一个循环!没有办法把这些分类!

一些排序算法无论如何都会返回一个没有正确排序的列表,但是Java使用的那个会完全混淆并抛出一个异常。

 类似资料:
  • 偏离变量只是包含以下字段的对象的一个实例: 附言时间对象是来自 Joda-Time 库的 DateTime 实例,TransportType 是包含常量火车、海船、驳船和卡车的枚举。 编辑: 好的,所以我将比较器编辑为以下内容: 但这显然违反了一般契约。我如何让它按时间排序,然后根据它们的其他属性对那些具有相等时间的对象进行排序,只关心它们是否相等?希望这有意义… 编辑:解决方案 谢谢大家回答我的

  • 有人能解释一下为什么我下面的比较器有时候会抛出上面的异常吗? 注意:myObject 中的 id 字段类型为 long。 解决方案: 基于@amit的回答

  • 问题内容: 您好,以下是我的比较器的比较方法。我不确定是什么问题。我在堆栈溢出时查找了其他类似标题的问题和答案,但不确定我的方法有什么问题,但我一直在获取java.lang.IllegalArgumentException:比较方法违反了它的一般约定! 任何帮助将不胜感激 添加我得到的异常 问题答案: 您的方法 不是可 传递的 。如果和,则必须等于。 现在考虑这种情况: 对于,和,假设方法返回以下

  • 我正在根据下面的比较器对集合进行排序。 这些值总是非空的。getOrderSendTime()对象属于java.util.Date类。 我知道这是一种传递性不一致,我认为这样的类不会有这样的问题。我搜索了未解决的问题,但没有找到有关该主题的任何问题。 有什么想法吗?

  • 我有时会得到一个 for 我可以始终如一地抛出此异常,实时数据运行足够长的时间,但我不确定如何解决问题的实际原因。 我的比较仪有什么问题?(具体来说,我违反了合同的哪一部分?)如何在不掩盖异常的情况下修复它? 我使用的是 Java 7,如果不进行重大重写就无法升级。 我可以通过将设置为来掩盖异常,但这不是一个理想的解决方案。 我尝试创建测试来随机生成数据并验证每个合同条件。我无法抛出异常。 我尝试

  • 问题内容: 为什么这样的代码 抛出此异常: 方法sre.getSponsored()返回一个布尔值。 谢谢。 问题答案: 我怀疑当 两个 值都 没有 赞助时就会出现问题。无论您用哪种方式返回1,即 那是无效的。 我建议您更改此: 至 在两个地方。我 实际上 可能会将此提取出具有此签名的方法: 然后这样称呼它: 这将使代码更清晰,IMO。