[Effective Java] 3 - item14 Comparable
을 구현할지 고려하라.
item14 Comparable
을 구현할지 고려하라.
compareTo
:Comparable
인터페이스의 유일무이한 메서드.- 자연적인 순서(natural order)가 존재하고, 이를 고려해야 한다면
Comparable
구현을 추가하자.Comparable
구현 객체는.sort()
를 사용해 정렬할 수 있다. (내부에서compareTo
를 사용해 정렬하므로)- 자동 정렬되는 컬렉션 관리도 쉽게 할 수 있다.
compareTo
메서드의 규약
x.compareTo(y)
에서 x와 y의 순서를 비교한다.
- x가 y보다 작으면 음의 정수를, 같으면 0을, 크면 양의 정수를 리턴한다.
- x와 비교할 수 없는 타입이 주어지면
ClassCaseException
을 던진다.
대칭성
Comparable
을 구현한 클래스는 모든 x, y에 대해sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
을 만족해야 한다.x.compareTo(y)
가 예외를 던지는 경우,y.compareTo(x)
도 예외를 던져야 한다.- 두 객체 참조의 순서를 바꿔 비교해도 예상한 결과가 나와야 한다.
추이성
Comparable
을 구현한 클래스는 모든 x, y, z에 대해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))
를 만족해야 한다.
equals
Comparable
을 구현한 클래스는 모든 x, y에 대해x.compareTo(y) == 0
이면,x.equals(y)
를 만족하는 것이 좋다. (필수 사항은 아니다.)- 이를 지키지 않는다면, 해당 클래스의 순서는 equals 메서드와 일관되지 않다고 명시해 주어야 한다.
compareTo
메서드 작성 요령
Comparable
은 제너릭 인터페이스이므로 메서드의 인수 타입은 컴파일 타임에 정해지며, 타입을 확인하거나 형변환 할 필요가 없다.null
을 인수로 넣으면NullPointerException
을 던져야 한다.Comparable
을 구현하지 않는 필드나, 표준이 아닌 순서로 비교해야 한다면 비교자(Comparator)를 대신 사용한다.- 비교자는 직접 만들거나 자바가 제공하는 것 중에 골라 쓸 수 있다.
- 과거에는 compareTo 매서드에서 관계 연산자인 <, >, = 을 사용하는 부분이 있었으나, java7 이후 기본 타입비교에는 박싱된 기본타입에 제공하는 정적 메서드를 권장한다.
public int compareTo(PhoneNumber pn) {
int result = Short.compare(this.areaCode, pn.areaCode);
if(result == 0) {
result = Short.compare(this.prefix, pn.prefix);
if(result == 0) {
result = Short.compare(this.line
Num, pn.lineNum);
}
}
}
- hashcode를 비교해 정렬하고자 할 때는 직접 연산해 비교시 계산 오류를 발생하거나 정수 오버플로가 발생할 수 있으므로, Comparator나 정적 메서드를 사용하자.
// 추이성에 위배되는 코드
static Comparator<Object> hashCodeOrder = new Comparator<>() {
(Object o1, Object o2) -> o1.hashCode() - o2.hashCode();
}
// 정적 메서드를 사용하는 방식
static Comparator<Object> hashCodeOrder = new Comparator<>() {
(Object o1, Object o2) -> Integer.compare(o1.hashCode(), o2.hashCode())
}
// Comparator를 사용하는 방식.
static Comparator<Object> hashCodeOrder = Comparator.comparingInt(o -> o.hashCode());
Leave a comment