Item 14 - Comparable을 구현할지 고려하라
compareTo 규약
Object.equals()
와 다르게 단순 동치성 비교 뿐만 아니라 순서 비교도 가능하며 제네릭하다.- 자기 자신이 (this)이
compareTo
에 전달된 객체보다 작으면 음수, 같으면 0, 크다면 양수를 리턴한다. - 반사성(A>B = B<A), 추이성(A<B, B<C 이면 A<C), 일관성(A=B이면, A와 C 비교결과 = B와 C 비교결과)을 만족해야 한다.
- 반드시 따라야 하는 것은 아니지만
x.compareTo(y) == 0
이라면x.equals(y)
가 true여야 한다.- 지키지 않을 경우, 해당 클래스의 객체를 컬렉션에 넣었을 때 해당 컬렉션이 구현한 인터페이스(
Collection
,Set
,Map
)에서 정의한 동작과 엇박자를 낼 수 있다. - 정렬된 컬렉션(
TreeSet
등)은 동치성 비교 시,equals
가 아닌compareTo
를 사용한다.
- 지키지 않을 경우, 해당 클래스의 객체를 컬렉션에 넣었을 때 해당 컬렉션이 구현한 인터페이스(
1
2
3
4
5
6
7
8
9
10
11
12
void example () {
BigDecimal number1 = new BigDecimal("1.0");
BigDecimal number2 = new BigDecimal("1.00");
Set<BigDecimal> set1 = new HashSet<>();
set1.add(number1);
set1.add(number2); // set1은 equals()로 비교하므로 원소가 2개
Set<BigDecimal> set2 = new TreeSet<>();
set2.add(number1);
set2.add(number2); // set2는 compareTo()로 비교하므로 원소가 1개
}
compareTo 구현 방법 1
- 자연적인 순서를 제공할 클래스에
implements Compratable<T>
을 선언한다. compareTo
메서드를 재정의한다.comprareTo
메서드 안에서 기본 타입은 박싱된 기본 타입의compare
를 사용해 비교한다.- 핵심 필드가 여러 개라면 비교 순서가 중요하다.
- 순서를 결정하는데 있어서 가장 중요한 필드를 먼저 비교하자.
- 그 값이 0이라면 다음 필드를 비교하자. (0이 아니면 순서가 거기서 순서가 결정된 것.)
- 기존 클래스를 확장하고 필드를 추가하는 경우 compareTo 규약을 지킬 수 없다.
- Composition을 활용할 것.
compareTo 구현방법 2
1
2
3
4
5
6
7
8
9
10
// 비교자 생성 메서드를 활용한 비교자
private static final Comparator<PhoneNumber> COMPARATOR =
comparintInt((PhoneNumber pn) -> pn.areaCode)
.thenComparingInt(pn -> pn.prefix)
.thenComparingInt(pn -> pn.lineNum); // 체이닝하여 순차적으로 필드 비교 가능
@Override
public int compareTo(PhoneNumber pn) {
return COMPARATOR.compare(this, pn);
}
- 자바 8부터 함수형 인터페이스, 람다, 메서드 레퍼런스와 Comprator가 제공하는 기본 메서드와 static 메서드를 사용해서 Comprator를 구현할 수 있다.
- Comparator가 제공하는 메서드 사용 방법
- Comparator의 static 메서드를 사용해서 Comparator 인스턴스 만들기
- 인스턴스를 만들었다면 default 메서드를 사용해서 메서드 호출 이어가기 (체이닝)
- static 메서드와 default 메소드의 매개변수로는 람다 표현식 또는 메서드 레퍼런스를 사용할 수 있다.
💡 핵심 정리
- 순서를 고려하는 값 클래스를 작성할 경우 반드시 Comparable 인터페이스를 구현하자.
- 구현함으로써 컬렉션을 통한 정렬, 검색, 비교 기능을 쉽게 사용할 수 있다.
- compareTo 메서드에서 필드 값 비교는 <, >이 아닌 정적
compare
메서드나 Comparator 인터페이스가 제공하는 비교자 생성 메서드를 사용하자.
This post is licensed under CC BY 4.0 by the author.