Java Integer compareTo() - why use comparison vs. subtraction?
Asked Answered
S

5

91

I've found that java.lang.Integer implementation of compareTo method looks as follows:

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

The question is why use comparison instead of subtraction:

return thisVal - anotherVal;
Smaragdite answered 28/4, 2010 at 10:59 Comment(2)
When we're so quick to worry about micro-optimization, we often end up with buggy code.Eulogy
As of JDK 7, one can use Integer.compare(thisVal, anotherVal) instead of writing out the ternary expression.Burke
P
105

This is due to integer overflow. When thisVal is very large and anotherVal is negative then subtracting the latter from the former yields a result that is bigger than thisVal which may overflow to the negative range.

Pepys answered 28/4, 2010 at 11:2 Comment(3)
Yeah the way they've done it here is probably more efficient than checking for overflow et alEfthim
Use Guava ComparisonChain. It is very handy! google.github.io/guava/releases/22.0/api/docs/com/google/common/…Ormandy
thisVal doesn’t need to be large. thisVal might be even zero and anotherVal be Integer.MIN_VALUE and you already have an overflow. And mind that, of course, it also could be the other way round, thisValue very small and anotherVal rather large, to have a distance that overflows the int value range.Hinterland
I
70

The subtraction "trick" to compare two numerical value is broken!!!

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

Here, a < b, yet a - b is positive.

DO NOT use this idiom. It doesn't work.

Moreover, even if it does work, it will NOT provide any significant improvement in performance, and may in fact cost readability.

See also

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

    This puzzle has several lessons. The most specific is: Do not use a subtraction-based comparator unless you are sure that the difference between values will never be greater than Integer.MAX_VALUE. More generally, beware of int overflow. Another lesson is that you should avoid "clever" code. Strive to write clear, correct code, and do not optimize it unless it proves necessary.

Ingrained answered 28/4, 2010 at 11:9 Comment(2)
It's not really broken at all. If you know anything about the numbers you're comparing, you'll probably know that they're safe to compare. Even not knowing, just ((long)a - b) ought to work. Though you're right; it's very rarely useful.Industrialist
@naiad just doing ((long)a - b) does not help, as you have to cast the result back to int, as that’s what the comparator has to return, ending up again with an overflow. You would have to do something like Long.signum on the result, which is easy to forget, as your comment shows. And it might not even be more efficient than Integer.compare, which the JVM might handle intrinsically…Hinterland
G
9

Simply speaking, the int type is not big enough to store the difference between two arbitrary int values. For example, the difference between 1.5 billion and -1.5 billion is 3.0 billion, but int cannot hold values greater than 2.1 billion.

Gelhar answered 28/4, 2010 at 12:3 Comment(0)
P
3

Perhaps it's to avoid overflow / underflow.

Phillips answered 28/4, 2010 at 11:2 Comment(0)
G
2

In addition to the overflow thing, you should note that the version with substraction does not give the same results.

  • The first compareTo version returns one of three possible values: -1, 0, or 1.
  • If you replace the last line with substraction, the result can be any integer value.

If you know there will be no overflow, you could use something like this:

public int compareTo(Integer anotherInteger) {
    return sign(this.value - anotherInteger.valuel);
}
Gassing answered 28/4, 2010 at 13:23 Comment(1)
You are correct that the results are not the same. But they are not required to be! compareTo is only required to return a negative value, zero or a positive value, depending on the sort order of this and the other object. See java.sun.com/j2se/1.5.0/docs/api/java/lang/…Peng

© 2022 - 2024 — McMap. All rights reserved.