Java Integer compareTo() - 为什么要使用比较而不是减法?

90

我发现java.lang.IntegercompareTo方法实现如下:

public int compareTo(Integer anotherInteger) {
    int thisVal = this.value;
    int anotherVal = anotherInteger.value;
    return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
}

问题是为什么要使用比较而不是减法:

return thisVal - anotherVal;

28
当我们太过关注微观优化时,往往会导致代码出现漏洞。 - Kevin Bourrillion
从JDK 7开始,可以使用Integer.compare(thisVal, anotherVal)代替写三元表达式。 - Stuart Marks
5个回答

105

这是由于整数溢出导致的。当thisVal非常大且anotherVal为负数时,从前者中减去后者会得到一个比thisVal更大的结果,可能会溢出到负范围。


是的,他们在这里的做法可能比检查溢出等更有效。 - rogerdpack
1
使用Guava ComparisonChain非常方便!请访问https://google.github.io/guava/releases/22.0/api/docs/com/google/common/collect/ComparisonChain.html。 - Andrea Bergonzo
thisVal 不需要很大。thisVal 可能甚至为零,而 anotherValInteger.MIN_VALUE,你已经发生了溢出。当然,也可能相反,thisValue 非常小,而 anotherVal 相对较大,以产生超出 int 值范围的距离。 - Holger

68

减法“技巧”比较两个数值已经失效了!!!

        int a = -2000000000;
        int b =  2000000000;
        System.out.println(a - b);
        // prints "294967296"

在这里,a < b,但是a - b是正数。

不要使用这个习惯用语,它行不通。

而且,即使它确实可行,它也不会显著提高性能,反而可能会降低可读性。

另请参阅

  • Java Puzzlers Puzzle 65: A Strange Saga of Suspicious Sort

    这个谜题有几个教训。其中最具体的是:除非您确定值之间的差异永远不会大于Integer.MAX_VALUE,否则不要使用基于减法的比较器。更普遍地说,要注意int溢出。另一个教训是,应该避免“聪明”的代码。努力编写清晰、正确的代码,除非必要,否则不要对其进行优化。


2
它实际上并没有真正损坏。如果您了解要比较的数字任何信息,您可能知道它们是安全的进行比较。即使不知道,只需使用((long)a - b)。虽然您是正确的; 它很少有用。 - amara
4
@naiad 只是做 ((long)a - b) 是不够的,因为你仍需将结果强制转换回 int,这是比较器必须返回的类型,并最终导致溢出问题。你需要在结果上执行类似 Long.signum 的操作,但很容易忘记,正如你的注释所示。而且,这种方法甚至可能不如 Integer.compare 更有效率,因为JVM可能会内部处理它… - Holger

9

简单来说,int类型不足以存储两个任意int值之间的差异。例如,15亿和-15亿之间的差异是30亿,但int无法存储大于21亿的值。


3
也许是为了避免溢出/下溢。

2

除了溢出的问题,你还需要注意使用减法的版本不会得到相同的结果

  • 第一个compareTo版本返回三个可能的值之一:-1、0或1。
  • 如果你用减法替换最后一行,结果可以是任何整数值。

如果你知道不会发生溢出,你可以使用以下代码:

public int compareTo(Integer anotherInteger) {
    return sign(this.value - anotherInteger.valuel);
}

13
你是正确的,结果并不相同。但这也不是必须的!compareTo只需要根据this和另一个对象的排序顺序返回负值、零或正值即可。请参见http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Comparable.html#compareTo%28T%29。 - Christian Semrau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接