[알고리즘] 35. Comparator 완전 정복
지난 글에서는 Java 정렬 사용법에 대해 정리했습니다. 이번 글에서는 Java 정렬에서 가장 많이 헷갈리는 부분인 Comparator에 대해 자세히 알아보겠습니다.
Comparator는 정렬 기준을 직접 만들 때 사용하는 도구입니다. 숫자를 오름차순이나 내림차순으로 정렬하는 것뿐 아니라, 문자열 길이순, 여러 조건 정렬, 객체 정렬까지 처리할 수 있습니다.
Comparator는 두 값을 비교해서 어떤 값이 앞에 올지 결정하는 정렬 기준입니다.
1. Comparator란?
Comparator는 Java에서 정렬 기준을 직접 정의할 때 사용하는 인터페이스입니다. 기본 정렬이 아니라 원하는 기준으로 정렬하고 싶을 때 사용합니다.
예를 들어 숫자는 기본적으로 오름차순 정렬됩니다.
int[] numbers = {5, 2, 8, 1, 3};
Arrays.sort(numbers);
하지만 문자열을 길이순으로 정렬하거나, 학생 객체를 점수순으로 정렬하려면 기본 정렬만으로는 부족합니다. 이때 Comparator를 사용합니다.
Arrays.sort(words, (a, b) -> a.length() - b.length());
위 코드는 문자열을 길이가 짧은 순서로 정렬합니다.
Comparator는 기본 정렬이 아닌 사용자 정의 정렬 기준을 만들 때 사용합니다.
2. compare(a, b)의 의미
Comparator의 핵심은 compare(a, b)입니다. 두 값 a와 b를 비교해서 어떤 값이 앞에 올지 결정합니다.
| 반환값 | 의미 | 결과 |
|---|---|---|
| 음수 | a가 b보다 앞에 온다 | a → b |
| 0 | 순서를 바꾸지 않는다 | 현재 순서 유지 |
| 양수 | b가 a보다 앞에 온다 | b → a |
처음에는 이 반환값이 헷갈릴 수 있습니다. 간단히 말하면 음수가 나오면 a가 앞, 양수가 나오면 b가 앞입니다.
Comparator의 핵심 규칙은 음수면 앞 순서 유지, 양수면 두 값의 순서 변경입니다.
3. 숫자 오름차순 정렬
숫자를 오름차순으로 정렬할 때는 작은 값이 앞에 와야 합니다. Comparator에서는 보통 아래처럼 작성합니다.
Integer[] numbers = {5, 2, 8, 1, 3};
Arrays.sort(numbers, (a, b) -> a - b);
System.out.println(Arrays.toString(numbers));
출력 결과는 다음과 같습니다.
[1, 2, 3, 5, 8]
a - b가 음수라면 a가 더 작다는 뜻이므로 a가 앞에 옵니다. 따라서 오름차순 정렬이 됩니다.
a - b → 오름차순
4. 숫자 내림차순 정렬
숫자를 내림차순으로 정렬하려면 큰 값이 앞에 와야 합니다. 이때는 b - a를 사용합니다.
Integer[] numbers = {5, 2, 8, 1, 3};
Arrays.sort(numbers, (a, b) -> b - a);
System.out.println(Arrays.toString(numbers));
출력 결과는 다음과 같습니다.
[8, 5, 3, 2, 1]
b - a를 사용하면 큰 값이 앞에 오게 됩니다.
b - a → 내림차순
오름차순은 a - b, 내림차순은 b - a 형태로 자주 작성합니다.
5. Integer.compare() 사용하기
a - b 방식은 간단하지만, 값의 범위가 매우 크면 오버플로우가 발생할 수 있습니다. 더 안전하게 비교하려면 Integer.compare()를 사용하는 것이 좋습니다.
Integer[] numbers = {5, 2, 8, 1, 3};
Arrays.sort(numbers, (a, b) -> Integer.compare(a, b));
System.out.println(Arrays.toString(numbers));
출력 결과는 다음과 같습니다.
[1, 2, 3, 5, 8]
내림차순은 비교 순서를 반대로 작성하면 됩니다.
Arrays.sort(numbers, (a, b) -> Integer.compare(b, a));
| 정렬 | Comparator |
|---|---|
| 오름차순 | Integer.compare(a, b) |
| 내림차순 | Integer.compare(b, a) |
숫자 범위가 크다면 a - b보다 Integer.compare()가 더 안전합니다.
6. 문자열 사전순 정렬
문자열은 compareTo()를 사용해 사전순으로 비교할 수 있습니다.
String[] words = {"banana", "apple", "carrot"};
Arrays.sort(words, (a, b) -> a.compareTo(b));
System.out.println(Arrays.toString(words));
출력 결과는 다음과 같습니다.
[apple, banana, carrot]
a.compareTo(b)는 a가 b보다 사전순으로 앞이면 음수를 반환합니다. 따라서 오름차순 사전순 정렬이 됩니다.
a.compareTo(b) → 사전순 오름차순
b.compareTo(a) → 사전순 내림차순
7. 문자열 길이순 정렬
문자열을 사전순이 아니라 길이순으로 정렬하고 싶다면 length()를 기준으로 비교합니다.
String[] words = {"banana", "kiwi", "apple", "fig"};
Arrays.sort(words, (a, b) -> a.length() - b.length());
System.out.println(Arrays.toString(words));
출력 결과는 다음과 같습니다.
[fig, kiwi, apple, banana]
길이가 짧은 문자열부터 정렬되었습니다.
더 안전하게 쓰고 싶다면 Integer.compare()를 사용할 수 있습니다.
Arrays.sort(words, (a, b) -> Integer.compare(a.length(), b.length()));
8. 여러 조건 정렬
알고리즘 문제에서는 정렬 기준이 하나만 있는 경우보다 여러 개인 경우가 많습니다. 예를 들어 단어를 다음 기준으로 정렬해보겠습니다.
- 길이가 짧은 단어가 먼저 온다.
- 길이가 같으면 사전순으로 정렬한다.
String[] words = {"banana", "apple", "kiwi", "fig", "car"};
Arrays.sort(words, (a, b) -> {
if (a.length() != b.length()) {
return a.length() - b.length();
}
return a.compareTo(b);
});
System.out.println(Arrays.toString(words));
출력 결과는 다음과 같습니다.
[car, fig, kiwi, apple, banana]
먼저 길이를 비교합니다. 길이가 다르면 길이 기준으로 정렬하고, 길이가 같으면 사전순으로 정렬합니다.
여러 조건 정렬은 1순위 조건을 먼저 비교하고, 같을 때 2순위 조건을 비교합니다.
9. 여러 조건 정렬 흐름
여러 조건 정렬은 아래 흐름으로 생각하면 됩니다.
1순위 조건이 다르다
→ 1순위 조건으로 정렬
1순위 조건이 같다
→ 2순위 조건으로 정렬
2순위 조건도 같다
→ 3순위 조건으로 정렬
예를 들어 학생을 정렬한다고 해보겠습니다.
- 점수가 높은 순서
- 점수가 같으면 나이가 어린 순서
- 나이도 같으면 이름 사전순
이런 경우 Comparator 안에서 조건을 순서대로 비교하면 됩니다.
10. 2차원 배열 정렬
2차원 배열 정렬에서도 Comparator를 자주 사용합니다. 대표적인 예는 좌표 정렬입니다.
다음 기준으로 정렬해보겠습니다.
- x값이 작은 순서로 정렬한다.
- x값이 같으면 y값이 작은 순서로 정렬한다.
int[][] points = {
{3, 4},
{1, 5},
{1, 2},
{2, 3}
};
Arrays.sort(points, (a, b) -> {
if (a[0] != b[0]) {
return a[0] - b[0];
}
return a[1] - b[1];
});
for (int[] point : points) {
System.out.println(point[0] + " " + point[1]);
}
출력 결과는 다음과 같습니다.
1 2
1 5
2 3
3 4
먼저 x값을 비교하고, x값이 같을 때 y값을 비교했습니다.
11. 2차원 배열에서 기준 반대로 하기
이번에는 x값은 큰 순서로, x값이 같으면 y값은 작은 순서로 정렬해보겠습니다.
int[][] points = {
{3, 4},
{1, 5},
{1, 2},
{3, 1}
};
Arrays.sort(points, (a, b) -> {
if (a[0] != b[0]) {
return b[0] - a[0];
}
return a[1] - b[1];
});
for (int[] point : points) {
System.out.println(point[0] + " " + point[1]);
}
출력 결과는 다음과 같습니다.
3 1
3 4
1 2
1 5
x는 내림차순, y는 오름차순으로 정렬되었습니다. 기준마다 방향이 다를 수 있으므로 문제 조건을 정확히 확인해야 합니다.
12. 객체 정렬
Comparator는 객체 정렬에서도 자주 사용됩니다. 예를 들어 학생 객체를 점수 기준으로 정렬해보겠습니다.
import java.util.ArrayList;
import java.util.Collections;
class Student {
String name;
int score;
Student(String name, int score) {
this.name = name;
this.score = score;
}
}
public class Main {
public static void main(String[] args) {
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("Kim", 80));
students.add(new Student("Lee", 95));
students.add(new Student("Park", 90));
Collections.sort(students, (a, b) -> b.score - a.score);
for (Student student : students) {
System.out.println(student.name + " " + student.score);
}
}
}
출력 결과는 다음과 같습니다.
Lee 95
Park 90
Kim 80
점수가 높은 순서로 정렬되었습니다.
13. 객체 여러 조건 정렬
객체 정렬에서도 여러 조건을 사용할 수 있습니다. 이번에는 학생을 다음 기준으로 정렬해보겠습니다.
- 점수가 높은 순서로 정렬한다.
- 점수가 같으면 이름 사전순으로 정렬한다.
Collections.sort(students, (a, b) -> {
if (a.score != b.score) {
return b.score - a.score;
}
return a.name.compareTo(b.name);
});
점수가 다르면 점수 기준으로 정렬합니다. 점수가 같을 때만 이름을 비교합니다.
객체 정렬에서는 어떤 필드를 1순위로 볼지, 어떤 필드를 2순위로 볼지 정하는 것이 중요합니다.
객체 정렬은 필드별 우선순위를 정확히 정하는 것이 핵심입니다.
14. Comparator.comparing() 사용하기
Java에서는 Comparator.comparing()을 이용해 객체 정렬을 더 읽기 좋게 작성할 수도 있습니다.
students.sort(Comparator.comparing(student -> student.name));
위 코드는 학생 이름 기준으로 오름차순 정렬합니다. 점수 기준으로 정렬하려면 다음처럼 작성할 수 있습니다.
students.sort(Comparator.comparingInt(student -> student.score));
점수를 내림차순으로 정렬하려면 reversed()를 붙일 수 있습니다.
students.sort(Comparator.comparingInt((Student student) -> student.score).reversed());
다만 알고리즘 문제에서는 람다 Comparator 방식이 더 직관적인 경우도 많습니다. 익숙한 방식으로 정확하게 작성하는 것이 중요합니다.
15. Comparator에서 자주 쓰는 패턴
Comparator에서 자주 쓰는 패턴을 정리해보겠습니다.
| 목표 | 코드 |
|---|---|
| 숫자 오름차순 | (a, b) -> a - b |
| 숫자 내림차순 | (a, b) -> b - a |
| 안전한 오름차순 | (a, b) -> Integer.compare(a, b) |
| 안전한 내림차순 | (a, b) -> Integer.compare(b, a) |
| 문자열 사전순 | (a, b) -> a.compareTo(b) |
| 문자열 길이순 | (a, b) -> a.length() - b.length() |
처음에는 이 패턴들을 자주 보고 따라 쓰면서 익숙해지는 것이 좋습니다.
16. Comparator에서 자주 하는 실수
Comparator를 사용할 때는 아래 실수를 조심해야 합니다.
- 오름차순과 내림차순 방향을 반대로 작성하는 경우
- compare() 반환값의 의미를 잘못 이해하는 경우
- 여러 조건 정렬에서 1순위 조건이 같은 경우를 처리하지 않는 경우
- 문자열 비교에 compareTo()를 사용하지 않는 경우
- 2차원 배열에서 a[0], a[1] 기준을 헷갈리는 경우
- 객체 정렬에서 필드 우선순위를 잘못 적용하는 경우
- a - b 방식에서 오버플로우 가능성을 고려하지 않는 경우
특히 여러 조건 정렬에서는 조건의 순서가 매우 중요합니다. 문제에서 요구한 우선순위를 그대로 코드에 반영해야 합니다.
1순위 조건 비교
→ 같으면 2순위 조건 비교
→ 또 같으면 3순위 조건 비교
Comparator 문제의 핵심은 조건의 우선순위를 정확히 코드로 옮기는 것입니다.
17. 정리
이번 글에서는 Comparator에 대해 정리했습니다.
- Comparator는 정렬 기준을 직접 만들 때 사용한다.
- compare(a, b)의 반환값으로 두 값의 순서를 결정한다.
- 음수면 a가 앞에 오고, 양수면 b가 앞에 온다.
- 숫자 오름차순은 a - b, 내림차순은 b - a 형태를 자주 사용한다.
- 큰 수 비교에서는 Integer.compare()가 더 안전하다.
- 문자열 사전순 비교에는 compareTo()를 사용한다.
- 여러 조건 정렬은 1순위 조건을 먼저 비교하고, 같을 때 다음 조건을 비교한다.
- 2차원 배열과 객체 정렬에서도 Comparator를 자주 사용한다.
Comparator는 Java 정렬에서 반드시 익숙해져야 하는 개념입니다. 처음에는 반환값이 헷갈릴 수 있지만, “어떤 값이 앞에 와야 하는가”를 기준으로 생각하면 점점 자연스러워집니다.
Comparator의 핵심은 두 값을 비교해 원하는 정렬 순서를 직접 만드는 것입니다.
다음 글 예고
다음 글에서는 투 포인터에 대해 알아보겠습니다.
정렬된 배열이나 연속 구간에서 두 개의 포인터를 움직이며 조건을 만족하는 값을 찾는 방법을 예제로 정리해보겠습니다.

'Problem Solving > Algorithm' 카테고리의 다른 글
| [알고리즘] 37. 슬라이딩 윈도우 (0) | 2026.07.20 |
|---|---|
| [알고리즘] 36. 투 포인터 (0) | 2026.07.19 |
| [알고리즘] 34. Java 정렬 사용법 (0) | 2026.07.17 |
| [알고리즘] 33. 정렬 알고리즘 개념 (0) | 2026.07.16 |
| [알고리즘] 32. 최단 거리 기초 (1) | 2026.07.15 |