Skip to main content

[Java] Comparable vs Comparator


1. Comparable이란?

  • 객체 내부에 정렬 기준을 직접 구현
  • 자기 자신이 "나는 이렇게 정렬될 거야"라고 말하는 구조
  • compareTo() 메서드 오버라이딩
class Person implements Comparable<Person> {
    String name;
    int age;

    @Override
    public int compareTo(Person o) {
        return this.age - o.age; // 나이 오름차순
    }
}

2. Comparator란?

  • 외부에서 정렬 기준을 따로 정의
  • 여러 기준으로 정렬하거나, 기존 클래스를 수정할 수 없을 때 유용
  • 익명 클래스나 람다식으로 간결하게 구현 가능
// 이름 기준 오름차순
Comparator<Person> byName = (p1, p2) -> p1.name.compareTo(p2.name);

// 나이 기준 내림차순
Comparator<Person> byAgeDesc = Comparator.comparingInt((Person p) -> p.age).reversed();

3. Comparator 체이닝 (복합 정렬)

정렬 기준이 여러 개일 경우, 체이닝으로 묶을 수 있다.

// 회원 목록을 최근 로그인순 → 나이 내림차순 → 이름 오름차순 정렬
Comparator<Member> memberComparator = Comparator
    .comparing(Member::getLastLogin).reversed()
    .thenComparing(Member::getAge, Comparator.reverseOrder())
    .thenComparing(Member::getName);
list.sort(
    Comparator.comparing(Person::getAge) // 나이 오름차순
              .thenComparing(Person::getName) // 나이가 같으면 이름순
);

4. Arrays.sort vs Collections.sort

메서드

내부 정렬 방식

특징

Arrays.sort

DualPivotQuickSort / TimSort

기본형 배열 정렬

Collections.sort

TimSort (Java 7+)

List 계열 정렬, 안정 정렬(stable sort)


5. Stream에서도 정렬 가능

List<Person> sorted = people.stream()
    .sorted(Comparator.comparing(Person::getAge).reversed()
        .thenComparing(Person::getName))
    .collect(Collectors.toList());

6. 언제 무엇을 써야 할까?

Comparable vs Comparator 비교

항목

Comparable

Comparator

정의 위치

객체 자신이 직접 정렬 기준을 정의 (compareTo)

외부에서 정렬 기준을 정의 (compare)

사용 목적

기본 정렬 기준을 정의할 때

다양한 정렬 기준을 따로 정의할 때

인터페이스

java.lang.Comparable<T>

java.util.Comparator<T>

구현 방식

public class Stage implements Comparable<Stage>

Collections.sort(list, comparator)

장점

코드 간결, 객체 자체 기준

유연한 다중 기준, 정렬 기준 변경 쉬움

단점

하나의 정렬 기준만 정의 가능

익명 클래스나 람다 써야 해서 코드 길어질 수 있음


7. 실무에서 성능 차이?

  • 두 방식 모두 TimSort 기반이라 성능은 거의 동일하다. 정렬 속도 자체에는 차이가 없다.
  • 성능보단 유연성과 구조의 차이이다. 실무에서는 보통 Comparator + 람다식 조합이 자주 쓰인다고 한다.
  • 성능은 비슷하지만, 유지보수성과 유연성에서 Comparator가 더 유리하기 때문이다.
  • compareTocompare()는 절대 ==을 피하고 Integer.compare() 또는 Double.compare()를 사용하는 게 안전하다.

상황

많이 쓰는 방식

정렬 기준이 딱 하나일 때

Comparable

다양한 정렬 기준이 필요한 리스트 (정렬 옵션 버튼)

Comparator

정렬 기준이 자주 바뀌거나 동적일 때, 라이브러리

Comparator + 람다

복합 정렬 (날짜, 우선순위 등)

Comparator + 메서드 체이닝