compareTo는 단순 동치성 비교에 순서까지 비교할 수 있고 제네릭하다. Comparable을 구현했다는 건 클래스의 인스턴스들에게 순서가 있음을 뜻한다.
compareTo는 객체와 주어진 객체의 순서를 비교한다. 객체가 주어진 객체보다 작다면 음의 정수, 크다면 양의 정수, 같다면 0을 반환한다. 비교할 수 없는 타입이라면 ClassCastException 을 던진다.
마지막 사항은 지키는것을 권고한다. 이를 따르지 않는 대표적은 클래스인 BigDecimal 을 예로 들어보자.
new BigDecimal("1.0")과 new BigDecimal("1.00")는 equals 메서드로 하면 다르기 때문에 HashSet은 두 개의 원소를 갖는다.
하지만, TreeSet은 compareTo를 사용하기 때문에 하나의 원소만 갖게 된다.
Comparable은 타입을 인수로 받는 제너릭 인터페이스다. 그렇기 때문에 인수 타입은 컴파일 타임에 정해지고 null 을 넣으면 NPE 을 던져야한다.
만약, 클래스에 핵심 필드가 여러 개라면 필드의 비교 순서를 정하는 것이 중요하다.
-> 핵심적인 필드부터 비교해가는게 중요
public int compareTo(PhoneNumber pn){
int result = Short.compare(areaCode, pn.areaCode); // 가장 중요한 필드
if(result == 0){
result = Short.compare(prefix, pn.prefix); // 두번쨰로 중요한 필드
if(result == 0){
result = Short.compare(lineNum, pn.lineNum); // 세번째로 중요한 필드
}
}
}
필드의 정렬 우선순위를 정해 같은 값이 있을 때마다 조건을 추가한다.
private static final Comparator<PhoneNumber> COMPARATOR =
comparingInt((PhoneNumber pn) -> pn.areaCode)
.thenComparingInt(pn -> pn.prefix)
.thenComparingInt(ph -> pn.lineNum);
public int compareTo(PhoneNumber pn) {
return COMPARATOR.compare(this, pn);
}
public int compareTo (int x, int y) {
return x < y ? 1 : (x == y) ? 0 : -1;
}
static Comparator<Object> hashCodeOrder = new Comparator<>() {
(Object o1, Object o2) -> o1.hashCode() - o2.hashCode();
}
아래와 같이 고쳐서 사용하는 것이 좋다
static Comparator<Object> hashCodeOrder = new Comparator<>() {
public int compare(Object o1, Object o2) {
return Integer.compare(o1.hashCode(), o2.hashCode());
}
};
static Comparator<Object> hashCodeOrder =
Comparator.comparingInt(o -> o.hashCode());