代码之家  ›  专栏  ›  技术社区  ›  WestFarmer

为什么compareTo不应返回Integer.MIN_VALUE

  •  0
  • WestFarmer  · 技术社区  · 1 年前

    我正在使用SonarQube。有一个 rule 针对java语言:

    它是符号,而不是从 相比之下,这很重要。返回Integer.MIN_VALUE不会传递 更高程度的不平等,这样做可能会导致错误,因为 compareTo的返回值有时与预期值相反 负值变成正值。然而,反转 整数.MIN_VALUE产生整数.MIN_VALUE,而不是 整数.MAX_VALUE。

    问题是SonarQube认为这是一个bug,而不是代码气味。在什么情况下这会导致错误?

    有人能举个例子吗?

    2 回复  |  直到 1 年前
        1
  •  4
  •   alalalala    1 年前

    原因就在这里

    Integer a = -1;
    Integer b = Integer.MIN_VALUE;
    
    System.out.println(b); // -2147483648
    System.out.println(-b); // -2147483648
    
    System.out.println(a); // -1
    System.out.println(-a); // 1
    

    如果要使用compareTo的结果进行判断,例如:

    Integer a = x.compareTo(y)
    
    
    if(-a > 0) {
        
        //do something
    
    }
    

    如果的返回值 compareTo Integer.MIN_VALUE ,则的值 -a 等于的值 a 两者都是 -2147483648 ,所以结果是错误的

        2
  •  2
  •   Sweeper    1 年前

    假设你回来了 MIN_VALUE 以下为:

    class PossiblyBadlyWrittenClass implements Comparable<PossiblyBadlyWrittenClass> {
        @NotNull private final int value;
    
        @Override
        public int compareTo(@NotNull PossiblyBadlyWrittenClass o) {
            if (value > o.value) {
                return Integer.MAX_VALUE;
            } else if (value < o.value) {
                return Integer.MIN_VALUE;
            } else {
                return 0;
            }
        }
    
        // constructor, and other boilerplate...
    }
    

    现在有其他人来使用这个 PossiblyBadlyWrittenClass 在他们班上。他们希望他们班的自然秩序 颠倒 如何排序 可能的错误WrittenClass 已订购。

    有人会这样做的一种方法是否定你的任何实现 compareTo 返回。他们会认为通过使用 + ,如果您 比较函数 返回一个正数,那么他们的将返回一个负数,反之亦然。

    class SomethingElse implements Comparable<SomethingElse> {
        @NotNull private final PossiblyBadlyWrittenClass foo;
    
        @Override
        public int compareTo(@NotNull SomethingElse o) {
            return -foo.compareTo(o.foo);
        }
    
        // ...
    }
    

    但事实并非如此!当你 比较函数 退货 Integer.MIN_VALUE (负数),应用一元 - 它的操作员会给你 整数.MIN_VALUE 再次,因为溢出。

    最小值(_V) -2147483648 从数学上讲,如果你否定它,你得到 2147483648 但是 Integer.MAX_VALUE 2147483647 ,只小一点。因此,数学上正确的结果不能表示为 int 。该值“环绕”到负数。

    所以现在他们 比较函数 有一个错误。

    当然,你可能会争辩说这是那个人的错,因为他们没有考虑到这个边缘案例。他们应该这样写:

    return o.foo.compareTo(foo);
    

    但后来人们使用 那个 代码也需要小心。如果你再也不回来会容易得多 最小值(_V) 首先,所以没有人需要担心这种边缘情况。