java - 比较方法违反了它的一般约定 - Java 错误
问题描述
我已经使用排序包装器定义了一个比较器。你能解释一下为什么这段代码会抛出一个异常,“比较方法违反了它的一般合同!”?如果您能告诉我如何解决它,我将不胜感激。
Ordering<Foo> order = new Ordering<Foo>() {
@Override
public int compare(Foo left, Foo right) {
return getCompare(orderMap, left.getItemId(), right.getItemId());
}
};
Collections.sort(Foos, order);
比较:
private int getCompare(Map<Long, Integer> orderMap, Long leftId, Long rightId) {
int indexLeft = orderMap.get(leftId) == null ? -1 : orderMap.get(leftId);
int indexRight = orderMap.get(leftId) == null ? -1 : orderMap.get(rightId);
if (indexLeft < 0 || indexRight < 0) {
return 1;
}
return Integer.compare(indexLeft, indexRight);
}
解决方案
这是合同:
- 如果 `a.compare(b) 是 X,并且 b.compare(c) 是 X,那么 a.compare(c) 也必须是 X,无论 X 是负数、正数还是零。
- 如果
a.compare(b)
是 X,那么b.compare(a)
必须是 -X:0 仍然是 0,-1 变成 +1,等等。 a.compare(a)
必须为 0。
而已。您的比较方法在很多方面打破了这一点。例如,您的第二行中有一个错误(肯定是orderMap.get(rightId) == null
,您可以改用它来清理它getOrDefault
),如果找不到任何索引或小于 0,您的代码总是返回 1,这违反了规则 ( a.compare(b)
,其中 a 不在地图中,返回 1,也b.compare(a)
将返回 1。它需要返回一个负数)。
如果其中一个不在地图中,您将不得不想出一个规则来处理会发生什么。如果您的代码是在假设它不会发生的情况下编写的,那么它是 - 当您的假设不成立时抛出异常,以便您可以调查为什么您的假设(所有提供的 left/rightIds 始终在地图中并且始终非负数)。正如所写的那样,如果发生这种情况,您的代码会以一种令人讨厌的方式直接上升——这就是异常的用途。以易于调试的方式展开。
如果这是意图,您将不得不制定一些规则。例如:如果a
在地图中但b
不在地图中,那么 a 总是高于 b。这意味着if (indexLeft < 0 && indexRight >= 0) return -1
而且if (indexLeft >= 0 && indexRight < 0) return +1;
,为了遵守规则。这就留下了一个问题:如果两者都不在怎么办。您可以选择没有办法订购它们(返回 0),但要知道这意味着您不能在 aTreeMap
或TreeSet
- 但排序一个清单,很好。允许单独的不可比较的,它们最终会以任意顺序聚集在一起。这并不违反规则。
推荐阅读
- wordpress - 如何重置我的 WordPress 管理员密码?
- reactjs - 如何更改反应选择上的图标?
- handlebars.js - 当我将 '.handlebars' 放在文档末尾时它可以工作,而当我把 '.hbs' 放在它不工作时
- php - 哈希长度扩展攻击中的填充导致 php 中的反序列化失败
- .net - 运行测试时未找到框架“Microsoft.NETCore.App”,版本“5.0.0”
- xml - XML 摘要值不正确
- c++ - 在 0/1 背包问题中,使用 2D 向量记忆子问题会超出时间限制,而使用 2D 数组也是如此
- svg - 您可以缩短 SVG 线以自动为箭头腾出空间吗?
- java - 如何在android中更新应用程序安装屏幕上的文本
- node.js - Cookie 解析器不工作/无法读取未定义的属性“jwt”