1 minute read

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