[Java][Effective Java] item 14. Comparable을 구현할지 고려하라

2022. 7. 6. 12:54JAVA/Effective Java

1. Comparable을 구현할때 무엇을 고려해야 하는가?

  • 알파벳, 숫자, 연대같이 순서가 명확한 값 클래스를 정의한다면 반드시 Comparable 인터페이스를 구현하자.
  • Collection, Set, Map과 같은 인터페이스는 비교를 할때 Object.equals 메서드를 사용하지 않고 Comparable.compareTo 메서드를 사용하기 때문에 컬렉션과 같은 인터페이스에 인스턴스를 넣을때 Comparable을 구현하자.
  • Comparable을 구현하지 않은 필드나 표준이 아닌 순서로 비교해야 한다면 비교자(Comprator)를 대신 사용하자.
  • compareTo 메서드에서 관계 연산자 < 와 >를 사용하는 이전 방식은 오류를 유발할 가능성이 있습니다.
  • 클래스의 필드 멤버가 여러개 있고 비교해야 한다면 핵심적인 필드부터 비교하자. 여기서 핵심적인 필드는 두 인스턴스의 정보가 다를 가능성이 높은 정보입니다.

 

2. compareTo 메서드의 일반 규약

compareTo 메서드는 객체와 주어진 객체의 순서를 비교합니다. 이 객체가 주어진 객체보다 작으면 음수 정수를, 같으면 0을, 크면 양의 정수를 반환합니다. 만약 이 객체와 비교할 수 없는 타입의 객체가 주어지면 ClassCastException을 던집니다.

 

다음은 compareTo 메서드의 일반 규약 내용입니다.

  • Comparable을 구현한 클래스는 모든 x, y에 대해서 sgn(x.compareTo(y)) == -sgn(y.compareTo(x))여야 합니다.
  • Comparable을 구현한 클래스는 추이성을 보장해야 합니다. 즉, (x.compareTo(y) > 0 && y.compareTo(z) > 0)이면 x.compareTo(z) > 0입니다.
  • Comparable을 구현한 클래스는 모든 z에 대해 x.compareTo(y) == 0이면 sgn(x.compareTo(z)) == sgn(y.compareTo(z))여야 합니다.
  • (x.compareTo(y) == 0) == (x.equals(y))여야합니다.

 

3. compareTo 구현

기본 타입 필드가 여럿일 때의 비교자

	// 기본 타입 필드가 여럿일 때의 비교자, 방법 1
	@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;
	}

 

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

	// 비교자 생성 메서드를 이용한 방법, 방법 2
	// 비교자 생성 메서드 Comparator.comparingInt, Comparator.thenComparing
	private static final Comparator<PhoneNumber> COMPARATOR =
			Comparator.comparingInt((PhoneNumber pn) -> pn.areaCode)
					  .thenComparing(pn -> pn.prefix)
					  .thenComparing(pn -> pn.lineNum);
	@Override
	public int compareTo(PhoneNumber pn) {
		return COMPARATOR.compare(this, pn);
	}

 

References

source code : https://github.com/yonghwankim-dev/effective_java/tree/master/src/role14
effective java 3/E