Java - Comparable (Feat. Effective Java)

순서를 고려해야 하는 값 class 를 작성한다면 꼭 Comparable Interface 를 구현해서, 해당 인스턴스들을 쉽게 정렬하고, 검색하고, 비교 기능을 제공하는 컬렉션과 어우러지도록 해야 한다.


compareTo 메서드에서 필드의 값을 비교할 때 < 와 > 연산자는 쓰지 말자. 대신, 박싱된 기본 타입 클래스가 제공하는 정적 compare 메서드나 Comparator Interface 가 제공하는 비교자 생성 메서드를 사용하자.


먼저, compareTo 를 구현할 때 3가지 규약을 살펴보자. equals 규약과 비슷하다.


1. 대칭성 - 두 객체 참조의 순서를 바꿔 비교해도 얘상한 결과가 나와야 한다.



2. 추이성 - 첫 번째가 두 번째보다 크고 두 번째가 세 번째보다 크면, 첫 번째는 세 번째보다 커야 한다.



3. 반사성 - 크기가 같은 객체들끼리는 어떤 객체와 비교하더라도 항상 같아야 한다.



반사성에서 한 가지 주의할점은 equals 와 compareTo 를 일관되게 구현해야 된다는 점인데, 일관되지 않을 경우, Collection 을 사용할 때 의도와 다르게 작동할 수 있다.

Bigdecimal 의 예를 보자. 아래의 javadoc 을 살펴보자.



두 객체의 equals 메서드의 경우 다르다고 나온다. 왜냐면 equals 메서드가 scale 여부까지 비교한다.
하지만, compareTo 는 값이 같은지 비교하기 때문에, 같다고 나온다.
따라서 이와 같이 BigDecimal 을 사용할 때, 주의하지 않으면 의도치 않은 버그가 발생할 수 있다.


더욱이, 아래와 같이 Collection 을 사용할 경우, 더욱이 주의해야 한다. HashSet 은 equals 를 기반으로, TreeSet 의 경우 compareTo 를 기반으로 비교하기 때문에, 이와 같은 결과가 나타난다.



https://stackoverflow.com/questions/6787142/bigdecimal-equals-versus-compareto

https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html


마지막으로, 해시코드로 Comparator 의 compare 혹은 Comparable 의 compareTo 를 구현하지 말자.

해당 방식은 int 의 overflow 를 일으키거나, IEEE 754 부동소수점 계산 방식에 따른 오류를 낼 수 있다.
따라서, 대안으로 아래의 2가지 방법을 사용해야 한다.


댓글

이 블로그의 인기 게시물

About JVM Warm up

About idempotent

About Kafka Basic

About ZGC

sneak peek jitpack

Spring Boot Actuator readiness, liveness probes on k8s

About Websocket minimize data size and data transfer cost on cloud

About G1 GC

대학생 코딩 과제 대행 java, python, oracle 네 번째