안드로이드 개발자 노트
[이펙티브 코틀린] Item42. compareTo의 규약을 지켜라 본문
compareTo 메서드는 수학적인 부등식으로 변환되는 연산자입니다.
obj1 > obj2 // obj1.compareTo(obj2) > 0
obj1 < obj2 // obj1.compareTo(obj2) < 0
obj1 >= obj2 // obj1.compareTo(obj2) >= 0
obj1 <= obj2 // obj1.compareTo(obj2) <= 0
compareTo 메서드는 Comparable<T> 인터페이스에도 들어 있습니다.
어떤 객체가 이 인터페이스를 구현하고 있거나 compareTo라는 연산자 메서드를 갖고 있다는 의미는 해당 객체가 어떤 순서를 갖고 있으므로, 비교할 수 있다는 것입니다.
compareTo는 다음과 같이 동작해야 합니다.
- 비대칭적 동작: a >= b 이고 b >= a 라면, a == b 여야 한다. 즉, 비교와 동등성 비교에 어떠한 관계가 있어야 하며, 서로 일관성이 있어야 한다.
- 연속적 동작: a >= b 이고 b >= c 라면, a >= c 여야 한다. 마찬가지로 a > b 이고 b > c 라면, a > c 여야 한다. 이러한 동작을 하지 못하면, 요소 정렬이 무한 반복에 빠질 수 있다.
- 코넥스적 동작: 두 요소는 어떤 확실한 관계를 갖고 있어야 한다. 즉, a >= b 또는 b >= a 중에 적어도 하나는 항상 true여야 한다. 두 요소 사이에 관계가 없으면, 퀵 정렬과 삽입 정렬 등의 고전적인 정렬 알고리즘을 사용할 수 없다.
compareTo를 따로 정의해야 할까?
일반적으로 어떤 프로퍼티 하나를 기반으로 순서를 지정하는 것으로 충분하여 compareTo를 따로 정의하는 상황은 거의 없습니다.
여러 프로퍼티를 기반으로 정렬해야 한다면, sortedWith 함수를 사용하면 됩니다.
이 함수는 compareBy를 활용해서 비교기(comparator)를 만들어서 사용합니다.
val sorted = names.sortedWith(compareBy({ it.surname }, { it.name }))
문자열은 알파벳과 숫자 등의 순서가 있는데, 내부적으로 Comparable<String>를 구현하고 있어서 순서 비교가 가능합니다.
// 이렇게 하지 마세요.
print("Kotlin" > "Java") // true
// "Kotlin".compareTo("Java") > 0
객체가 자연스러운 순서를 갖기 어렵다면, 비교기(comparator)를 사용하는 것이 좋습니다.
이를 자주 사용한다면, 클래스에 companion 객체로 만들어 두는 것도 좋습니다.
class User(val name: String, val surname: String) {
// ...
companion object {
val DISPLAY_ORDER = compareBy(User::surname, User::name)
}
}
val sorted = names.sortedWith(User.DISPLAY_ORDER)
compareTo 구현하기
compareTo를 구현할 때 유용하게 활용할 수 있는 톱레벨 함수가 있습니다.
두 값을 단순하게 비교하기만 한다면, compareValues 함수를 다음과 같이 활용할 수 있습니다.
class User(
val name: String,
val surname: String
): Comparable<User> {
override fun compareTo(other: User): Int =
compareValues(surname, other.surname)
}
더 많은 값을 비교하거나, 선택기(selector)를 활용해서 비교하고 싶다면, 다음과 같이 comapreValuesBy를 사용합니다.
class User(
val name: String,
val surname: String
): Comparable<User> {
override fun compareTo(other: User): Int =
compareValuesBy(this, other, { it.surname }, { it.name })
}
'Kotlin > 이펙티브 코틀린' 카테고리의 다른 글
[이펙티브 코틀린] Item43. API의 필수적이지 않는 부분을 확장 함수로 추출하라 (0) | 2024.01.14 |
---|---|
[이펙티브 코틀린] Item41. hashCode의 규약을 지켜라 (0) | 2024.01.13 |
[이펙티브 코틀린] Item40. equals의 규약을 지켜라 (1) | 2024.01.13 |