본문 바로가기

STUDY/이펙티브자바

3-5) Comparable을 구현할지 고려하라

Comparable 인터페이스, compareTo 메소드

 

public class Customer implements Comparable<Customer> {
    private int customerId;
    ...
    @Override
    public int compareTo(Customer o) {
        return Integer.compare(this.customerId, o.customerId);
    }
    ...
}

// customerList가 customerId 기준으로 정렬된다.
Arrays.sort(customerList);

Comparable 인터페이스는 compareTo 메소드를 가지고있다. compareTo 메소드는 두 객체를 비교하고 그 결과를 반환한다. 얼핏 equals 메소드와 비슷해 보일 수 있지만, equals는 두 객체의 논리적 동일성을 판단하고 compareTo는 두 객체의 선후관계를 비교하여 정렬에 사용된다. 그래서 Comparable을 구현한 클래스는 Arrays.sort를 호출하는 것 만으로 객체를 정렬할 수 있다.

 

 


compareTo 일반규약

 

compareTo는 동일성 비교가 아니라 선후관계를 비교하는것이기 때문에 참/거짓을 반환하는게 아니라 선후관계를 나타내는 -1,0,1을 반환한다. compareTo 메소드가 지켜야하는 일반규약을 아래와 같다.

  1. x.compareTo(y) = -y.compareTo(x)

  2. x.compareTo(y) > 0 이고 y.compareTo(z) 이면, x.compareTo(z) >0 이다

  3. x.compareTo(y) == 0 이면, x.compareTo(z) == y.compareTo(z) 이다.

  4. 권고사항 x.compareTo(y) == 0 이면, x.equals(y) == true 이다. 

 

 


compareTo 예시

 

// 비교 순서가 성능에 큰 영향을 끼친다.
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);
    }
    return result;
}

 

// Comparator를 사용하여 코드를 간결하게 하였다.
private static final Comparator<PhoneNumber> COMPARATOR = 
    Comparator.comparingInt((PhoneNumber pn) -> pn.areaCode)
        .thenComparingInt(pn -> pn.prefix)
        .thenComparingInt(pn -> pn.lineNum);

public int compareTo(PhoneNumber pn) {
    return COMPARATOR.compare(this, pn);
}

compareTo에서 여러 필드의 값들을 비교한다면 비교하는 순서가 성능에 영향을 준다. 핸드폰 번호를 비교한다고 하면 010 부분은 대부분이 동일하기 때문에 변별력을 주지 못하고 연산비용만 낭비할 것이다. 변별력이 있을걸로 예상되는 필드를 가장 먼저 비교하는것이 효율적이다.

728x90