Java Integer compareTo()-为什么使用比较与减法?

Java Integer compareTo()-为什么使用比较与减法?,java,optimization,integer,comparison,integer-overflow,Java,Optimization,Integer,Comparison,Integer Overflow,我发现java.lang.Integer方法的compareTo实现如下所示: public int compareTo(Integer anotherInteger) { int thisVal = this.value; int anotherVal = anotherInteger.value; return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1)); } 这是由于整数溢出造成的。当t

我发现
java.lang.Integer
方法的
compareTo
实现如下所示:

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

这是由于整数溢出造成的。当
thisVal
非常大且另一个
值为负值时,从前者中减去后者会产生大于
thisVal
的结果,该值可能会溢出到负值范围。

可能是为了避免溢出/下溢。

减法“技巧”比较两个数值是不正确的

        int a = -2000000000;
        int b =  2000000000;
        System.out.println(a - b);
        // prints "294967296"
这里,
a
,然而
a-b
是正的

不要使用这个成语。它不起作用

此外,即使它确实有效,它也不会在性能上提供任何显著的改进,而且实际上可能会降低可读性成本

另见
  • 谜题65:一个可疑的奇怪故事 这个难题有几个教训。最具体的是:不要使用基于减法的比较器,除非您确定值之间的差值永远不会大于Integer.MAX_值
。更一般地说,要小心
int
溢出。另一个教训是,您应该避免使用“聪明”的代码。努力编写清晰、正确的代码,除非证明有必要,否则不要对其进行优化


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

除了溢出的内容外,您应该注意带减法的版本不会给出相同的结果

  • 第一个compareTo版本返回三个可能值之一:-1、0或1
  • 如果用减法替换最后一行,结果可以是任何整数值
如果您知道不会出现溢出,您可以使用以下方法:

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

当我们很快就开始担心微观优化时,我们经常会遇到错误代码。从JDK 7开始,我们可以使用
整数。比较(thisVal,anotherVal)
而不是写出三元表达式。结果不一样是正确的。但他们不是必须的
compareTo
只需返回负值、零值或正值,具体取决于
和其他对象的排序顺序。看,它一点也没坏。如果你知道你正在比较的数字,你可能知道比较它们是安全的。即使不知道,只要
((long)a-b)
就行了。虽然你是对的;它很少有用。@naiad仅仅执行
((长)a-b)
没有帮助,因为您必须将结果转换回
int
,因为这是比较器必须返回的结果,结果再次溢出。您必须对结果执行类似于
Long.signum
的操作,正如您的评论所示,这很容易忘记。它甚至可能不会比Integer.compare更有效,JVM可能会从本质上处理这一点……是的,他们在这里所做的工作可能比检查溢出和alUse Guava ComparisonChain更有效。它非常方便
thisVal
不需要很大
thisVal
甚至可能是零,而另一个val
可能是
Integer.MIN\u值,并且您已经有了溢出。请注意,当然,它也可能是另一种情况,
thisValue
非常小,而
anotherVal
相当大,其距离超出
int
值范围。
public int compareTo(Integer anotherInteger) {
    return sign(this.value - anotherInteger.valuel);
}