작성 정보

- 작성일 : 2026-05-29

- 관련 문제 : PG42579 베스트 앨범

- 관련 문서 : Comparator 정렬 기준, Map 정렬과 computeIfAbsent

Comparable은 객체가 자기 자신의 기본 정렬 기준을 가지게 만드는 인터페이스다. Song끼리는 어떤 순서로 놓을지, Genre끼리는 어떤 순서로 놓을지를 객체 안에 직접 정의할 때 사용한다.

Comparable을 쓰는 기준

객체에 자연스럽고 대표적인 정렬 기준이 하나 있다면 Comparable을 고려한다.

상황선택
객체의 기본 정렬 기준이 분명하다Comparable
상황마다 정렬 기준이 바뀐다Comparator
정렬이 한 번만 필요하고 간단하다람다 Comparator
같은 타입을 여러 기준으로 정렬한다Comparator를 여러 개 만든다

베스트 앨범에서는 Song의 정렬 기준이 문제 안에서 거의 고정된다. 재생 횟수 내림차순, 동률이면 고유 번호 오름차순이다. 그래서 Song implements Comparable<Song>로 둘 수 있다.

compareTo 반환값

compareToComparator와 같은 반환 규칙을 가진다.

this.compareTo(other)가 음수면 this가 앞에 온다
this.compareTo(other)가 양수면 other가 앞에 온다
this.compareTo(other)가 0이면 같은 순서다

예를 들어 Song에서 재생 횟수가 큰 노래가 앞에 와야 한다면 다음처럼 쓴다.

@Override
public int compareTo(Song other) {
    return Integer.compare(other.playCount, this.playCount);
}

this.playCount가 100이고 other.playCount가 300이면 Integer.compare(300, 100)은 양수다. 양수면 other가 앞에 온다. 그래서 재생 횟수 내림차순이 된다.

동률 조건 넣기

정렬 기준이 여러 개면 우선순위가 높은 조건부터 비교한다.

@Override
public int compareTo(Song other) {
    if (this.playCount != other.playCount) {
        return Integer.compare(other.playCount, this.playCount);
    }
    return Integer.compare(this.index, other.index);
}
조건방향코드
재생 횟수내림차순Integer.compare(other.playCount, this.playCount)
고유 번호오름차순Integer.compare(this.index, other.index)

동률 조건을 빼먹으면 예제는 맞아도 숨은 테스트에서 틀릴 수 있다.

Comparable 객체끼리 비교하기

Comparable을 구현한 객체는 직접 비교할 수 있다.

Song a = new Song(0, 500);
Song b = new Song(1, 300);

int result = a.compareTo(b);

result가 음수면 a가 앞이다. 양수면 b가 앞이다.

정렬 API도 내부적으로 이 기준을 사용한다.

songs.sort(Song::compareTo);
Collections.sort(songs);

Map.Entry.comparingByValue()도 value가 Comparable이면 그 기준을 사용한다.

genreMap.entrySet().stream()
        .sorted(Map.Entry.comparingByValue());

여기서 value인 GenreComparable<Genre>를 구현하고 있어야 자연스럽게 정렬된다.

주의할 점

compareTo에서 뺄셈을 쓰는 습관은 피한다.

return other.playCount - this.playCount;

이 방식은 짧지만 값 범위가 커지면 오버플로우 위험이 있고, 정렬 방향도 헷갈리기 쉽다.

대신 다음처럼 쓴다.

return Integer.compare(other.playCount, this.playCount);

실수 체크

  • 객체의 기본 정렬 기준이 하나로 고정되는가
  • this.compareTo(other)가 음수면 this가 앞이라는 기준을 기억했는가
  • 내림차순이면 Integer.compare(other, this) 방향인지 확인했는가
  • 동률 조건을 문제에 나온 순서대로 처리했는가
  • 뺄셈 비교 대신 Integer.compare를 썼는가