CompareTo 메서드란
Comparable 인터페이스의 유일한 메서드이다. equals처럼 동작하지만, 추가적으로 순서까지 비교할 수 있다. (반환 값이 1이면 더 큰 값, 0이면 동일한 값, -1이면 작은 값을 의미한다) Comparable을 구현했다는 것은 그 클래스의 인스턴스들 간에 자연적인 순서가 있음을 뜻한다.
그래서 Comparable을 구현한 객체의 배열은 손쉽게 정렬할 수 있다.
Arrays.sort(a);
Java
복사
Comparable의 힘
Comparable을 구현하면 이 인터페이스를 활용하는 수많은 제네릭 알고리즘과 컬렉션의 힘을 누릴 수 있다. 알파벳, 숫자, 연대 같이 순서가 명확한 값 클래스를 작성한다면 반드시 Comparable 인터페이스를 구현하자.
CompareTo의 규약
1.
반사성 : 두 객체 참조의 순서를 바꿔 비교해도 예상한 결과가 나와야 한다.
2.
추이성 : 첫 번째보다 두번 째 객체가 크고, 두 번째 객체가 세 번째 객체보다 크면, 세 번째 객체는 첫 번째 객체보다 커야한다.
3.
대칭성 : 크기가 같은 객체들 끼리는 어떤 객체와 비교하더라도 항상 같아야 한다.
이 세가지 규칙은 equals와 같고(item 10), 그렇기에 주의사항과 우회법이 같다.
주의사항은 기존 클래스를 확장한 구현체에서 새로운 값을 추가하면 compareTo 규약을 지킬 수 없다는 것이고, 우회법은 상속보다는 조합을 사용하고 조합된 필드에 대한 뷰 메서드(getter)를 활용하는 것이다.
동치성 비교에서 equals와 동일한 결과를 반환하는 것도 중요하다. TreeSet처럼 순서가 중요한 컬렉션에선 동치성을 비교할 때 equlas가 아닌 compareTo를 사용한다.
구현시의 주의사항
Comparable은 제네릭 인터페이스이므로 입력 인수의 타입을 확인하거나 형변환 하지 않아도 된다.
내부 필드 중 객체 참조 필드는 compareTo를 재귀적으로 호출하고, Comparable을 구현하지 않은 필드는 Comparator을 대신 활용한다. Comparator는 직접 구현해도 되고 자바 라이브러리에서 재공하는 것을 사용해도 된다.
원시 타입인 경우 랩핑 클래스의 정적 메서드 compareTo를 이용하면 된다.
핵심 필드가 여럿 인 경우 핵심적인 필드부터 비교해나가자. 비교 결과가 0이 아니라면 곧장 반환하자. 핵심이 되는 필드가 동일하다면, 똑같지 않은 필드를 찾을 때 까지 비교해 나간다.
Comparator의 비교자 생성 메서드
자바 8 부터는 Comparator 인터페이스가 메서드 체이닝 방식으로 Comparator를 구성할 수 있게 되었다.
// Comparable with comparator construction methods
private static final Comparator<PhoneNumber> COMPARATOR =
comparingInt((PhoneNumber pn) -> pn.areaCode)
.thenComparingInt(pn -> pn.prefix)
.thenComparingInt(pn -> pn.lineNum);
public int compareTo(PhoneNumber pn) {
return COMPARATOR.compare(this, pn);
}
Java
복사
약간의 성능저하가 있을 수 있어 유의해야 한다.
용어정리
한글명 | 영어명 |
비교자 생성 메서드 | comparator construction method |