【问题标题】:Java 8 Comparison method violates its general contract issue in comparator [duplicate]Java 8比较方法违反了比较器中的一般合同问题[重复]
【发布时间】:2017-11-16 05:10:03
【问题描述】:

当我使用下面的比较器对对象进行排序时,比较方法违反了比较器中的一般合同问题。

final Set<Span> set = new TreeSet<Span>(new Comparator<Span>() {

        public int compare(final Span firstSpan, final Span secSpan) {
            BigInteger s1X0 = firstSpan.getCoordinates().getX0();
            BigInteger s1X1 = firstSpan.getCoordinates().getX1();
            BigInteger s2X0 = secSpan.getCoordinates().getX0();
            BigInteger s2X1 = secSpan.getCoordinates().getX1();

            BigInteger s1Y0 = firstSpan.getCoordinates().getY0();
            final BigInteger s2Y0 = secSpan.getCoordinates().getY0();

            if(s1X0.intValue() == s2X0.intValue() && s1X1.intValue() == s2X1.intValue() && s1Y0.intValue() == s2Y0.intValue()){
                return 0;
            }
            if ((s1Y0.intValue() - s2Y0.intValue() <= 5) && (s1Y0.intValue() - s2Y0.intValue() >= -5)) {
                return (s1X0.intValue()>s2X0.intValue()) ? 1 : -1;
            } else {
                if ((s1X0.intValue() >= s2X0.intValue() && s1X0.intValue() <= s2X1.intValue())
                        || (s2X0.intValue() >= s1X0.intValue() && s2X0.intValue() <= s1X1.intValue())) {
                    return (s1Y0.intValue() > s2Y0.intValue()) ? 1 : -1;
                } else {
                    return s1X0.intValue() > s2X0.intValue() ? 1 : -1;
                }
            }

        }

    });

【问题讨论】:

  • 鉴于你调用了intValue() 24 次,你为什么不直接制作s1X0int 变量呢?这样可以更轻松地为您提供帮助,并使您的代码更易于阅读。
  • 如果您能告诉我们您想要达到的目标,并且最好提供一个minimal reproducible example 来演示问题,这也会有所帮助 - 给出具体示例,我们应该很容易向您展示您的比较不一致的地方。
  • 你明白那个错误信息是什么意思吗?仔细阅读java.util.Comparator 的API 文档,其中解释了compare 方法的实现要求。您的实现违反了这些要求,因此您必须检查代码并对其进行调整以确保其符合要求。
  • return s1X0.intValue() &gt; s2X0.intValue() ? 1 : -1; 在我看来不是可传递的(如果值相等会发生什么?)。
  • 从哪里开始?使用BigInteger 表明值可能超出int 范围,否则,您为什么使用BigInteger?因此,仅基于int 值进行比较容易出错。您还使用减法而不检查溢出。除此之外,你能用简单的语言解释比较器的逻辑吗?然后,重新检查代码是否真的遵循这个逻辑?

标签: java sorting java-8 comparator


【解决方案1】:

Comparator 必须对其比较的对象施加总排序。特别是这意味着它必须是可传递的,即如果a 小于b,并且b 小于c,那么a 必须小于c。您的 Comparator 没有该属性。

考虑以下示例:

a.getX0() == 1    b.getX0() == 2    c.getX0() == 3
a.getX1() == 4    b.getX1() == 5    c.getX1() == 6
a.getY0() == 4    b.getY0() == 0    c.getY0() == -4

那么它认为a小于b(y0的差小于5),b小于c(y0的差小于5),但是@987654334 @不小于c(y0的差大于5,所以取y0的值)。

这三个对象应该按什么顺序排序?

此外,您的代码还有其他问题。如果您将所有内容都转换为int,则可能会发生溢出(这也可能导致您提到的异常)。当数据存储为BigInteger 时,您还应该使用BigIntegers 进行比较,例如使用BigInteger.subtractBigInteger.compare 方法。

【讨论】:

    【解决方案2】:

    通过使用 BigInteger.intValue,您只是假设所有数字都适合简单整数。

    由于 BigInteger 是 Comparable,您应该依赖 BigInteger.compare 而不是比较 int 值。

    【讨论】:

    • 这应该只是一个评论,而不是一个完整的答案。
    • 由于我没有所需的声誉,我无法评论其他人的答案,...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 2021-12-05
    • 1970-01-01
    • 2015-10-10
    • 1970-01-01
    相关资源
    最近更新 更多