【问题标题】:Collections.sort() Fails In large ArrayList, Frequently sortedCollections.sort() 在大型 ArrayList 中失败,经常排序
【发布时间】:2014-10-13 07:46:55
【问题描述】:

我看过很多与此问题相关的帖子,但我执行的每一次桌面检查和我实施的建议都没有帮助。我不知道我是如何违反比较器的合同的。当然,我不经常使用比较器。

我有一个很大的 ArrayList 对象,每次更新都会对它们进行排序,因为它们的位置经常变化。我必须按照从左下角到右上角的顺序渲染这些对象,以保持 2D 程序的“深度”外观。

这是我的比较器:

@Override
public int compare(RenderObject o1, RenderObject o2) 
{
    //if(o1 == null || o2 == null)
    //    return 0;

    if(o1 == null)
        return -1;
    else if(o2 == null)
        return 1;

    //vertices in order top-left, top-right, bottom-right, bottom-left
    PointF[]    bounds1 = o1.getVertices(),
                bounds2 = o2.getVertices();

    //if(bounds1 == null || bounds2 == null || bounds1.equals(bounds2))
    //  return 0;

    if(bounds1 == null)
        return -1;
    else if(bounds2 == null)
        return 1;

    if(bounds1[0].x >= bounds2[1].x || bounds1[3].y <= bounds2[0].y)
        return 1;
    else if(bounds1[1].x <= bounds2[0].x || bounds1[0].y >= bounds2[3].y)
        return -1;

    return o1.getZOrder() < o2.getZOrder() ? 1 : (o1.getZOrder() > o2.getZOrder() ? -1 : 0);
}

谁能解释一下违反合同的地方。我尝试对 o1 和 o2 使用相同的精确顶点进行桌面检查,但无法弄清楚它们是如何不相等的。如果无法帮助我想我将不得不手动实现排序,它可能会更有效,因为并非所有对象都会在每次更新时移动,但我仍然想修复此代码,如果没有其他参考的话。

编辑:这是实际的错误,但它是正确的,所有其他人都停止了这个问题。

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(Unknown Source)
at java.util.TimSort.mergeAt(Unknown Source)
at java.util.TimSort.mergeForceCollapse(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.Collections.sort(Unknown Source)
at ....Map.update(Map.java:237)
at ....GameMain.update(GameMain.java:76)
at ....BasicGame.start(BasicGame.java:173)
at ....GameMain.main(GameMain.java:121)

【问题讨论】:

  • 如果您无法弄清楚,作为权宜之计,您可以使用某些系统属性关闭此一致性检查。
  • 谢谢你,Thilo,这可能对将来有用,因为我真的想忽略这个,让我的渲染人员处理这个!
  • 顺便说一句,我真的很喜欢您在问题中提供的详细信息,既清晰又向我们提供了有关您尝试过的内容和所处位置的信息。您正是我们正在寻找的 Stack Overflow 贡献者。我已将此问题发送给我的追随者,因为我希望它可以帮助其他有同样问题的人。
  • 谢谢@jmort253 我很感激。我总是尽量记住在 SO 上发帖时打开我的详细设置;)

标签: java sorting arraylist


【解决方案1】:

你必须和null打交道吗?因为那可能是个问题。

现在,当涉及null 时,您返回“相等”。

所以 1

要修复它,要么在null 上出错(如果这是一个选项,您需要避免空值),或者将null 设为最小。

if (a == b) return 0;
if (a == null) return -1;
if (b == null) return 1;

此外,如果您执行&gt;=,则无法返回1-1。它可以是平等的,对吧?特别是,将对象与自身(或自身的克隆)进行比较必须返回0。这似乎是单元测试的好案例。

【讨论】:

  • 哦,我现在明白了。很棒的答案。 +1 基本上,您是说 null 在排序中的位置不明确。
  • 这是肯定的一件事 - 假设三个 RenderObject; abnull,其中 a &lt; b,然后是 compare(null,a) == 0,但 compare(null,b) != compare(a,b)
  • 当两者都为空时,您仍然需要返回 0。但也许问题在于非空情况。有很多||。这也可能是双向的,变得不一致。
  • 另外,如果您执行&gt;=,您将无法返回1-1。它可以是平等的,对吧?这似乎是单元测试的好案例。
  • 我想回应一下 Thilo 关于单元测试的说法。在我有一个接受各种输入并提供各种输出的小函数的情况下,它对我有很大帮助。单元测试可确保您可以调整代码,同时为您提供有关所有输出不正确的不同输入的实时反馈,反之亦然。
猜你喜欢
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 2017-05-07
  • 1970-01-01
  • 2018-10-11
  • 1970-01-01
相关资源
最近更新 更多