ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Item 14. Comparable을 구현할지 고려하라
    백수의 개발/이펙티브 자바 2019. 9. 29. 19:45

     

    Comparable의 compareTo()는 단순 동치성 비교뿐만 아니라 순서까지 비교할 수 있으며, 제네릭하다.

    따라서 Comparable을 구현했다는 것은 해당 클래스의 순서가 있음을 의미한다.

    그로 인해 아래와 같이 간단하게 정렬을 사용할 수 있는 객체가 된다.

     

    Arrays.sort(a);

     

    CompareTo 메서드의 일반 규약

    • 이 객체와 주어진 객체의 순서를 비교한다.
    • 이 객체가 주어진 객체보다 작으면 음의 정수(-1)를, 같으면 0을, 크면 양의 정수(1)를 반환한다.
    • 이 객체와 비교할 수 없는 타입이 주어지면 ClassCaseException을 던진다.

    1. 대칭성

    Comparable을 구현한 클래스는 모든 x, y에 대해 sgn(x.compareTo(y)) == -sgn(y.compareTo(x))여야 한다.

    따라서 x.compareTo(y)가 예외를 던지면, y.compareTo(x)도 예외를 던져야한다.

     

    2. 추이성

    (x.compareTo(y) > 0 && y.compareTo(z) > 0)이면 x.compareTo(z) > 0이다.

     

    3. 반사성

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

     

    4. equals

    이는 필수는 아니지만 꼭 지키는 것이 좋다.

    (x.compareTo(y) == 0) == (x.equals(y))이다. 이를 지키지 않는 모든 클래스는 그 사실을 명시해야한다.

    (* 주의 : 이 클래스의 순서는 equals 메서드와 일관되지 않다.)

     

    CompareTo 구현 패턴

    • 관계 연산자 "<", ">"를 사용하는 것은 거추장스럽고 오류를 유발하니 피해라.
    public int compareTo(int x, int y) {
    	return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
    • 기본타입인 경우 박싱된 기본타입 클래스의 compare()함수, 또는 비교 클래스 자체의 compare()을 사용해라.
    public int compareTo (int x, int y) {
    	return Integer.compare(x, y);
    }
    • 가장 핵심적인 필드부터 비교하자. 불필요한 연산을 줄여줄 것 이다.
    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.lineNum, pn.lineNum);
    		}
    	}
        return result;
    }
    • 비교자 생성 메서드를 활용한 비교자를 사용해도 된다.
    private static final Comparator<PhoneNumber> COMPARATOR 
    	= comparingInt((PhoneNumber pn) -> pn.areaCode)  
    		.thenComparingInt(pn -> pn.prefix)  
    		.thenComparingInt(pn -> pn.lineNum);
    
    public int compareTo(PhoneNumber pn){
    	return COMPARATOR.compare(this, pn);
    }

     

    마무리

    순서를 고려해야 하는 값 클래스를 작성한다면 꼭 Comparable 인터페이스를 구현하여, 그 인스턴스들을 쉽게 정렬하고, 검색하고, 비교 기능을 제공하는 컬렉션과 어우러지도록 해야 한다.

    compareTo 메서드에서 필드의 값을 비교할 때 "<"와 ">" 연산자는 쓰지 말도록 하자.

    대신 박싱된 기본 타입 클래스가 제공하는 정적 compare메서드나 Comparator 인터페이스가 제공하는 비교자 생성 메서드를 사용하자.

    댓글

Designed by Tistory.