본문 바로가기
Language/Effective java

모든 객체의 공통 메서드

by y.j 2022. 6. 11.
728x90

Comparable을 구현할지 고려하라

Comparable interface를 통해 인스턴스들에 작연적인 순서를 만들 수 있다. compareTo는 단순 동치성과 순서를 비교 할 수 있다. 알파벳, 숫자, 연대 같이 순서가 명확한 값 클래스를 작성한다면 반드시 Comparable interface를 구현하자.

public interface Comparable<T> {
    public int compareTo(T o);
}

 

compareTo 메서드의 일반 규약

이 객체와 주어진 객체의 순서를 비교한다.

· 나보다 작은 객체 음의 정수
· 나보다 같은 객체 0
· 나보다 큰 객체 양의 정수
· 비교 할 수 없는 경우 ClassCastException

규약 
1. sgn(x.compareTo(y)) == -sgn(y.xompareTo(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 (x.compareTo(y) == 0)  == (x.equals(y))
   * sgn 부호 함수 : 음일떄 -1, 0, 양일때 1

 

첫 번째 규약은 순서를 바꿔 비교해도 예상한 결과가 나와야 한다는 뜻이다. x와 y가 같다면 바꿔 비교해도 0이 나와야 하고 x.compare(y)가 1이었으면 y.compareTo(x)는 -1이 되어야 한다.

 

두 번째 규약은 추이성이다. x < y이고 y < z이면 x < z를 만족해야한다.

 

세 번째 규약은 크기가 같은 객체들끼리 어떻게 비교하더라도 항상 같아야 한다.

 

네 번째 규약은 권고지만 꼭 지켜야 한다. compareTo로 동치성이라면 equals도 동치성이여야 한다. 잘 지키지 않더라고 클래스는 여전히 잘 동작한다. 예를 들어 BigDecimal클래스가 있다. new BigDecimal("1.0")과 new BigDecimal("1.00")은 equals로 비교하면 서로 다르기 때문에 HashSet에서는 2개 원소를 갖게 된다. 

 

compareTo를 작성하는 방법

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<T>를 이용하는 방법

성능이 저하된다.

private static final Comparator<PhoneNumber> COMPARATOR = 
        comparingInt((PhoneNumber pn) -> pn.areaCode)
                .thenComparing(pn -> pn.prefix)
                .thenComparing(pn ->pn.lineNum);

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

 

해쉬코드를 이용하는 방법

해시코드의 값의 차를 기준으로 하는 방법을 쓰면 안된다. 추이성이 위배되고 오버플로우나 부동소수점 오류가 있다.

static Comparator<Object> hashCodeOrder = new Comparator<Object>() {
    @Override
    public int compare(Object o1, Object o2) {
        return o1.hashCode() - o2.hashCode();
    }
}

 

compare메서드를 이용하는 방법

static Comparator<Object> hashCodeOrder = new Comparator<Object>() {
    @Override
    public int compare(Object o1, Object o2) {
        return Integer.compare(o1.hashCode(), o2.hashCode());
    }
}

 

비교자 생성 메서드를 활용한 비교자

static Comparator<Object> hashCodeOrder = comparingInt(o -> o.hashCode());
728x90

'Language > Effective java' 카테고리의 다른 글

클래스와 인터페이스  (0) 2022.06.12
클래스와 인터페이스  (0) 2022.06.12
모든 객체의 공통 메서드  (0) 2022.06.07
모든 객체의 공통 메서드  (0) 2022.06.06
모든 객체의 공통 메서드  (0) 2022.06.06

댓글