Effective Java - 모든 객체의 공통 메서드(4)

SeungHyuk Shin·2021년 9월 16일
0

Effective Java

목록 보기
7/26
post-thumbnail

[아이템 14]. Comparable을 구현할지 고려하라


이번에는 Comparable 인터페이스의 유일무이한 메서드인 ComapreTo를 알아보자. 이번 장에서 다룬 다른 메서들과 다른 compareTo는 Object의 메서드가 아니다.

Comparable을 구현 했다는 것은 그 클래스의 인스턴스들에 자연적인 순서가 있음을 뜻한다.

Arrayas.sort(a);

Comparable을 구현하면 이 인터페이스를 활용하는 수많은 제너릭 알고리즘과 컬렉션의 힘을 누릴 수 있다. 좁쌀만한 노력으로 코끼리만 한 큰 효과를 얻는 것이다.

compareTo 메서드의 일반 규약은 equals의 규약과 비슷하다.

이 객체와 주어진 객체의 순서를 비교한다. 이 객체가 주어진 객체보다 작으면 음의 정수를, 같으면 0를, 크면 양의 정수를 반환한다. 잉 객체와 비교할 수 없는 타입의 객체가 주어지면 ClassCastException을 던진다.
다음 설명에서 sgn(표현식) 표기는 수학에서 말하는 부호 함수를 뜻하며, 표현식의 값이 음수,0,양수 일때 -1,0,1을 반환하도록 정의했다.

  • 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을 구현한 클래스는 추이성을 보장해야 한다. 즉, (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))여야 한다. Comparable을 구현하고 이 권고를 지키지 않는 모든 클래스는 그 사실을 명시해야 한다. 다음과 같이 명시하면 적당할 것이다.
    " 주의 : 이 클래스의 순서는 equals 메서드와 일관되지 않다 "

앞선 세 규약은 eqauls 규약과 똑같이 반사성, 대칭성, 추이성을 충족해야 함을 뜻한다. 마지막 규약은 필수는 아니지만 꼭 지키길 권한다. compareTo 순서와 equals 결과가 일관되지 않으면 구현한 인터페이스(Collection, Set, 혹은 Map)에 정의된 동작과 엇박자를 낼 것이다.

Comparable은 타입을 인수로 받는 제너릭 인터페이스이므로 compareTo 메서드의 인수 타입은 컴파일타임에 정해진다.

클래스에 핵심 필드가 여러개라면 어느 것을 먼저 비교하느냐가 중요해진다. 중요순서대로 비교해나다가 0이 아니라면 즉 순서가 결정되면 거기서 바로 리턴을 하면 된다.

자바 8에서는 COmparator 인터페이스가 일련의 비교자 생성메서드와 팀을 꾸려 메서드 연쇄 방식으로 비교자를 생성할 수 있게 되었다. 멋지게 구현할 수있고 간결함에 많은 프로그래머가 매혹되지만 성능은 10% 정도 나빠진다.

이따금 '값의 차'를 기준으로 첫 번째 값이 두 번 째 값보다 작으면 음수를, 두 값이 같으면 0을, 첫 번째 값이 크면 양수를 반환하는 compareTo나 compare 메서드와 마주 할 것이다. 여기 그 예를 가져왔다.

이 방식은 사용하면 안된다. 이 방식은 정수 오버플로를 일으키거나 IEEE 754 부동소수점 계산 방식에 따른 오류를 낼 수 있다. 그렇다고 이번 아이템에 설명한 방법대로 구현한 코드보다 월등히 빠르지도 않다. 정적 compare 메서드를 활용한 비교자나 Comparator를 구현해 비교를 하도록하자

0개의 댓글