Java Integer compareTo ()-왜 비교 대 빼기를 사용합니까?


80

나는 것으로 나타났습니다 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));
}

문제는 빼기 대신 비교를 사용하는 이유입니다.

return thisVal - anotherVal;

27
마이크로 최적화에 대해 너무 빨리 걱정하면 종종 버그가있는 코드로 끝납니다.
Kevin Bourrillion

JDK 7 Integer.compare(thisVal, anotherVal)부터는 삼항 표현식을 작성 하는 대신 사용할 수 있습니다 .
Stuart Marks

답변:


96

이것은 정수 오버플로 때문입니다. 경우 thisVal매우 크고, anotherVal그 이전부터 수율 인 결과 후자를 뺀 부정보다 더 큰 thisVal어떤 음 범위 넘칠 수있다.


그래 그들이 여기서 한 방식은 오버플로 등을 확인하는 것보다 더 효율적일 것입니다.
rogerdpack

Guava ComparisonChain을 사용하십시오. 매우 편리합니다! google.github.io/guava/releases/22.0/api/docs/com/google/common/...
안드레아 Bergonzo에게

thisVal클 필요가 없습니다. thisVal심지어 제로하고 수 anotherVal있을 Integer.MIN_VALUE당신은 이미 오버 플로우가있다. 물론 값 범위 를 초과하는 거리를 갖는 것은 둥글고 thisValue매우 작고 anotherVal다소 클 수도 int있습니다.
Holger

65

두 숫자 값을 비교하는 뺄셈 "트릭"이 깨졌습니다 !!!

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

여기, a < b아직 a - b긍정적입니다.

이 관용구를 사용하지 마십시오. 작동하지 않습니다.

또한, 이 작업을 수행하더라도 , 그것은 것입니다 NOT 사실 비용 가독성에 상당한 성능 향상, 그리고 5 월을 제공합니다.

또한보십시오

  • Java Puzzlers Puzzle 65 : 수상한 종류의 이상한 사가

    이 퍼즐에는 몇 가지 교훈이 있습니다. 가장 구체적인 내용은 다음과 같습니다. 값 간의 차이가 절대로 크지 않을 것이라는 확신이없는 한 빼기 기반 비교기를 사용하지 마십시오 Integer.MAX_VALUE . 보다 일반적으로 int오버플로에 주의하십시오 . 또 다른 교훈은 "영리한"코드를 피해야한다는 것입니다. 명확하고 올바른 코드를 작성하기 위해 노력하고 필요한 것으로 입증되지 않는 한 최적화하지 마십시오.


2
전혀 깨지지 않았습니다. 비교하려는 숫자에 대해 아는 것이 있으면 비교해도 안전하다는 것을 알 수 있습니다. 알지 못하더라도 ((long)a - b)일해야합니다. 당신이 옳지 만; 거의 유용하지 않습니다.
amara 2014 년

4
@naiad ((long)a - b)는 결과를 다시 캐스트 int해야하므로 비교기가 반환해야하므로 다시 오버플로가 발생하므로 도움이되지 않습니다 . 귀하 Long.signum의 의견에서 알 수 있듯이 잊기 쉬운 결과 와 같은 작업을 수행해야합니다 . 그리고 심지어는보다 효율적하지 않을 수 Integer.compareJVM이 ... 본질적으로 처리 할 수있는
홀거

9

간단히 말해서, int유형은 두 임의 int값 간의 차이를 저장할만큼 충분히 크지 않습니다 . 예를 들어 15 억에서 -15 억 사이의 차이는 30 억이지만 int21 억보다 큰 값을 가질 수 없습니다.


3

아마도 오버플로 / 언더 플로를 피하는 것입니다.


1

오버플로 외에도 빼기 있는 버전 은 동일한 결과를 제공하지 않는다는 점에 유의해야 합니다 .

  • 첫 번째 compareTo 버전은 -1, 0 또는 1의 세 가지 가능한 값 중 하나를 반환합니다.
  • 마지막 줄을 빼기로 바꾸면 결과는 정수 값이 될 수 있습니다.

오버플로가 없다는 것을 알고 있다면 다음과 같이 사용할 수 있습니다.

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

12
결과가 동일하지 않다는 것이 맞습니다. 그러나 반드시 그럴 필요는 없습니다! compareTo의 정렬 순서 this및 다른 개체 에 따라 음수 값, 0 또는 양수 값을 반환하는 데만 필요 합니다. java.sun.com/j2se/1.5.0/docs/api/java/lang/…
Christian Semrau
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.