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());
'Language > Effective java' 카테고리의 다른 글
클래스와 인터페이스 (0) | 2022.06.12 |
---|---|
클래스와 인터페이스 (0) | 2022.06.12 |
모든 객체의 공통 메서드 (0) | 2022.06.07 |
모든 객체의 공통 메서드 (0) | 2022.06.06 |
모든 객체의 공통 메서드 (0) | 2022.06.06 |
댓글