핵심 정리: compareTo 규약
Object 가 제공하는 메서드는 아니다.
Compile 시점에 체크가 가능하다.
Object.equals에 더해서 순서까지 비교할 수 있으며 Generic을 지원한다.
자기 자신이 (this)이 compareTo에 전달된 객체보다 작으면 음수, 같으면 0, 크 다면 양수를 리턴한다.
반사성, 대칭성, 추이성을 만족해야 한다.
public class CompareToConvention {
public static void main(String[] args) {
BigDecimal n1 = BigDecimal.valueOf(23134134);
BigDecimal n2 = BigDecimal.valueOf(11231230);
BigDecimal n3 = BigDecimal.valueOf(53534552);
BigDecimal n4 = BigDecimal.valueOf(11231230);
// p88, 반사성
System.out.println(n1.compareTo(n1));
// p88, 대칭성
System.out.println(n1.compareTo(n2));
System.out.println(n2.compareTo(n1));
// p89, 추이성
System.out.println(n3.compareTo(n1) > 0);
System.out.println(n1.compareTo(n2) > 0);
System.out.println(n3.compareTo(n2) > 0);
// p89, 일관성
System.out.println(n4.compareTo(n2));
System.out.println(n2.compareTo(n1));
System.out.println(n4.compareTo(n1));
// p89, compareTo가 0이라면 equals는 true여야 한다. (아닐 수도 있고..)
// BigDecimal 같은경우 해당되지 않는다.
BigDecimal oneZero = new BigDecimal("1.0");
BigDecimal oneZeroZero = new BigDecimal("1.00");
// 결과값 compareTo = 0 , equals = false;
System.out.println(oneZero.compareTo(oneZeroZero)); // Tree, TreeMap
System.out.println(oneZero.equals(oneZeroZero)); // 순서가 없는 콜렉션
}
}
반드시 따라야 하는 것은 아니지만 x.compareTo(y) == 0이라면 x.equals(y)가 true여야 한다.
핵심 정리: compareTo 구현 방법 1
자연적인 순서를 제공할 클래스에 implements Compratable<T> 을 선언한다.
public final class PhoneNumber implements Cloneable, Comparable<PhoneNumber> {
// 코드 14-2 기본 타입 필드가 여럿일 때의 비교자 (91쪽)
@Override
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;
}
compareTo 메서드를 재정의한다.
comprareTo 메서드 안에서 기본 타입은 박싱된 기본 타입의 compare을 사용 해 비교한다.
핵심 필드가 여러 개라면 비교 순서가 중요하다. 순서를 결정하는데 있어서 가장 중요한 필드를 비교하고 그 값이 0이라면 다음 필드를 비교한다.
기존 클래스를 확장하고 필드를 추가하는 경우 compareTo 규약을 지킬 수 없다.
Composition을 활용할 것.
상위 클래스의 Comparable 상속 후 하위 클래스에서의 Comparable 의 재상속 후에 다음과 같이 작성하는 것은 추천하지 않는다.
// anti pattern
public class NamedPoint extends Point {
public static void main(String[] args) {
NamedPoint p1 = new NamedPoint(1, 0, "keesun");
NamedPoint p2 = new NamedPoint(1, 0, "whiteship");
Set<NamedPoint> points = new TreeSet<>(new Comparator<NamedPoint>() {
@Override
public int compare(NamedPoint p1, NamedPoint p2) {
int result = Integer.compare(p1.getX(), p2.getX());
if (result == 0) {
result = Integer.compare(p1.getY(), p2.getY());
}
if (result == 0) {
result = p1.name.compareTo(p2.name);
}
return result;
}
});
// 필드 추가 하는 순간 equals 규약을 지키기 위해서는 상속을 하지 않고 다음과 같이
public class NamedPoint implements Comparable<NamedPoint> {
private final Point point;
private final String name;
public NamedPoint(Point point, String name) {
this.point = point;
this.name = name;
}
public Point getPoint() {
return this.point;
}
@Override
public int compareTo(NamedPoint namedPoint) {
int result = this.point.compareTo(namedPoint.point);
if (result == 0) {
result = this.name.compareTo(namedPoint.name);
}
return result;
}
}
핵심 정리: compareTo 구현 방법 2