아이템 14 : Comparable을 구현할지 고려하라
compareTo 메서드의 일반 규약은 equals의 규약과 비슷하다.
- Comparable을 구현한 클래스는 모든 x,y에 대해 sgn(x.compareTo(y)) == -sgn(y.compareTo(x))여야 한다(따라서 x.compareTo(y)는 y.compareTo(x)가 예외를 던질 때에 한해 예외를 던져야 한다).
- Comparable을 구현한 클래스는 추이성을 보장해야 한다. 즉, (x.compareTo(y) > 0 && y.compareTo(z) > 0)이면 x.compareTo(z) > 0이다.
- Comparable을 구현한 클래스는 모든 z에 대한 x.compareTo(y) == 0 이면 sgn(x.compareTo(z)) == sgn(y.compareTo(z))다.
- 이번 권고가 필수는 아니지만 꼭 지키는게 좋다. (x.compare(y) == 0) == (x.equals(y)) 여야 한다. Comparable을 구현하고 이 권고를 지키지 않는 모든 클래스는 그 사실을 명시해야 한다. 다음과 같이 명시하면 적당할 것이다.
"주의 : 이 클래스의 순서는 equals 메서드와 일관되지 않다."
첫 번째 규약은 두 객체 참조의 순서를 바꿔 비교해도 예상한 결과가 나와야 한다는 것이다. 즉, 첫 번째 객체가 두 번째 객체보다 작으면, 두 번째가 첫 번쨰보다 커야 한다. 첫 번째가 두번째와 크기가 같다면, 두 번째는 첫 번째와 같아야 한다. 마지막으로 첫 번째가 두 번째보다 크면, 두 번째는 첫 번쨰보다 작아야 한다.
두 번째 규약은 첫 번째가 두 번째보다 크고 두 번째가 세 번째보다 크면, 첫 번째는 세 번째보다 커야 한다는 뜻이다.
마지막 규약은 크기가 같은 객체들끼리는 어떤 객체와 비교하더라도 항상 같아야 한다는 뜻이다.
이상의 세 규약은 compareTo 메서드로 수행하는 동치성 검사도 equals 규약과 똑같이 반사성, 대칭성, 추이성을 충족해야 함을 뜻한다.
compareTo의 마지막 규칙은 필수는 아니지만 꼭 지키길 권한다. 마지막 규약은 간단히 말하면 compareTo 메서드로 수행한 동치성 테스트의 결과가 equals와 같아야 한다는 것이다.
Effective Java 2판에서는 compareTo 메서드에서 정수 기본 타입 필드를 비교할 때는 관계 연산자인 <와 >를, 실수 기본 타입 필드를 비교할 때는 정적 메서드인 Double.compare와 Float.compare를 사용하라고 권했다. 그런데 자바 7부터는 상황이 변했다. 박싱된 기본 타입 클래스들에 새로 추가된 정적 메서드인 compare를 이용하면 되는 것이다. compareTo 메서드에서 관계 연산자 <와 >를 사용하는 이전 방식은 거추장스럽고 오류를 유발하니, 이제는 추천하지 않는다.
핵심 정리
순서를 고려해야 하는 값 클래스를 작성한다면 꼭 Comparable 인터페이스를 구현하여, 그 인스턴스들을 쉽게 정렬하고, 검색하고, 비교 기능을 제공하는 컬렉션과 어우러지도록 해야 한다. compareTo 메서드에서 필드의 값을 비교할 때 <와 > 연산자는 쓰지 말아야 한다. 그 대신 박싱 기본 타입 클래스가 제공하는 정적 compare 메서드나 Comparator 인터페이스가 제공하는 비교자 생성 메서드를 사용하자.
'언어 > JAVA' 카테고리의 다른 글
[Effective Java] public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) | 2020.03.16 |
---|---|
[Effective Java] 클래스와 멤버의 접근 권한을 최소화하라 (0) | 2020.03.16 |
[Effective Java] clone 재정의는 주의해서 진행하라 (0) | 2020.03.15 |
[Effective Java] toString을 항상 재정의하라 (0) | 2020.03.14 |
[Effective Java] equals를 재정의하거든 hashCode도 재정의하라 (0) | 2020.03.14 |