Arrays.sort, Collections.sort, 커스텀 Comparator, 객체 정렬까지 정렬의 모든 것을 정리했습니다.
1️⃣ 기본 정렬
🔹 1-1. 기본 배열 정렬 (Arrays.sort)
- 기본형 배열은 Dual-Pivot Quicksort 사용 (평균 O(N log N))
- 참조형 배열은 TimSort 사용 (O(N log N))
1
2
3
int[] arr = {5, 1, 4, 2, 3};
Arrays.sort(arr); // 오름차순
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 4, 5]
🔹 1-2. 리스트 정렬 (Collections.sort)
- 내부적으로 List를 배열로 변환 후 TimSort 적용
- 오름차순은 자연 순서(Natural Order)로 동작
1
2
3
List<Integer> list = Arrays.asList(5, 1, 4, 2, 3);
Collections.sort(list); // 오름차순
System.out.println(list); // [1, 2, 3, 4, 5]
2️⃣ 내림차순 정렬
🔹 2-1. 배열 내림차순 (Integer[] 사용)
- 원시 자료형 불가능, 객체 자료형으로 선언 필수
- int[] 는 불가능 → Integer[]로 박싱해야 함
1
2
3
Integer[] arr = {5, 1, 4, 2, 3};
Arrays.sort(arr, Collections.reverseOrder());
System.out.println(Arrays.toString(arr)); // [5, 4, 3, 2, 1]
🔹 2-2. 리스트 내림차순
1
2
3
4
List<Integer> list = Arrays.asList(5, 1, 4, 2, 3);
list.sort(Collections.reverseOrder());
// Collections.sort(list, Collections.reverseOrder()) 도 가능
System.out.println(list); // [5, 4, 3, 2, 1]
3️⃣ 커스텀 정렬 (Comparator 사용)
🔹 3-1. 람다로 바로 정의
- 문자열 길이 기준 오름차순 정렬
a - b
대신Integer.compare(a, b)
권장 (오버플로 방지)
1
2
3
String[] arr = {"apple", "banana", "kiwi", "grape"};
Arrays.sort(arr, (a, b) -> Integer.compare(a.length(), b.length()));
System.out.println(Arrays.toString(arr)); // [kiwi, apple, grape, banana]
🔹 3-2. Collections.sort()에 바로 Comparator
1
2
3
4
5
6
7
8
9
10
List<String> list = Arrays.asList("apple", "banana", "kiwi", "grape");
Collections.sort(list, (a, b) -> b.compareTo(a)); // 내림차순
System.out.println(list); // [kiwi, grape, banana, apple]
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
4️⃣ 객체에서 정렬
🔹 4-1. Comparable 인터페이스 구현
- Comparable은 클래스 내부에서 기본 정렬 기준 정의
- Arrays.sort() / Collections.sort() 호출 시 자동 적용
- 예시: 사람(Person)을 나이(age) 오름차순 정렬
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Person implements Comparable<Person> {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
// Comparable 인터페이스 구현
@Override
public int compareTo(Person o) {
return Integer.compare(this.age, o.age); // 나이 오름차순
// return this.age - other.age; // 오름차순
// return o.age - this.age; // 내림차순
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
public class Main {
public static void main(String[] args) {
Person[] arr = {
new Person("Kim", 30),
new Person("Lee", 20),
new Person("Park", 25)
};
Arrays.sort(arr);
List<Person> list = new ArrayList<>();
list.add(new Person("Alice", 30));
list.add(new Person("Bob", 20));
list.add(new Person("Charlie", 25));
Collections.sort(list);
System.out.println(Arrays.toString(arr));
// [Lee (20), Park (25), Kim (30)]
}
}
🔹 4-2. Comparator로 외부에서 정렬 정의
- 정렬 시 Comparator를 익명 클래스/람다로 직접 전달
- 정렬 기준을 외부에서 유연하게 정의
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Arrays.sort(arr, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p2.name.compareTo(p1.name); // 이름 내림차순
}
});
Comparator<Person> comparator = new Comparator<Person>() { // 객체 정의
@Override
public int compare(Person a, Person b) {
return b.age - a.age; // 나이 내림차순
}
};
Collections.sort(list, comparator);
// 람다 이용
Arrays.sort(arr, (p1, p2) -> p1.name.compareTo(p2.name)); // 이름 오름차순
Collections.sort(list, (a, b) -> b.age - a.age); // 나이 내림차순
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Main {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("Alice", 30));
list.add(new Person("Bob", 20));
list.add(new Person("Charlie", 25));
// 1) 나이 오름차순
list.sort(new Comparator<Person>() {
@Override
public int compare(Person a, Person b) {
return a.age - b.age;
}
});
// 2) 또는 람다 사용 (Java 8+)
list.sort((a, b) -> a.age - b.age);
// 3) 이름 기준 내림차순
list.sort((a, b) -> b.name.compareTo(a.name));
System.out.println(list);
}
}
🔹 4-3. 다중 조건 정렬 (예: 나이 오름차순, 같으면 이름 사전순)
1
2
3
4
5
6
7
8
9
10
11
12
13
Arrays.sort(arr, (p1, p2) -> {
if (p1.age == p2.age) {
return p1.name.compareTo(p2.name);
}
return Integer.compare(p1.age, p2.age);
});
list.sort((a, b) -> {
if (a.age == b.age) {
return a.name.compareTo(b.name); // 이름 오름차순
}
return a.age - b.age; // 나이 오름차순
});
5️⃣ Stream 정렬
1
2
3
4
List<String> list = Arrays.asList("apple", "banana", "kiwi", "grape");
list.stream()
.sorted((a, b) -> b.length() - a.length()) // 길이 내림차순
.forEach(System.out::println);
정렬 시 주의할 점
- int[]는 Comparator 불가 → Integer[]로 변환
- compare(a, b)는
- 음수 → a < b
- 0 → a == b
- 양수 → a > b
- 문자열 비교는 compareTo() 사용 (사전순)
6️⃣ 전체 비교 정리
정렬 방법 | 적용 대상 | 정렬 기준 | 성능 (평균) | 특징 / 비고 |
---|---|---|---|---|
Arrays.sort(int[]) | 기본형 배열 (int[] , double[] 등) | 오름차순 (변경 불가) | O(N log N) (Dual-Pivot QuickSort) | 빠르고 메모리 효율적, Comparator 불가 |
Arrays.sort(Integer[]) | 참조형 배열 (Integer[] , String[] , 객체[]) | 오름/내림차순 Comparator 가능 | O(N log N) (TimSort) | null 허용, Comparator로 커스텀 가능 |
Collections.sort(List<T>) | List (ArrayList , LinkedList 등) | 오름/내림차순 Comparator 가능 | O(N log N) (TimSort) | 내부적으로 배열로 변환 후 정렬 |
List.sort(Comparator) | List | Comparator 필수 | O(N log N) (TimSort) | Java 8+, 람다 사용에 적합 |
Comparable 구현 | 객체 배열 / 리스트 | compareTo() 로 정의된 기본 정렬 | O(N log N) | 클래스 내부에서 기본 정렬 규칙 고정 |
Comparator 구현 | 객체 배열 / 리스트 | 외부에서 다중 조건 가능 | O(N log N) | 람다식 활용 가능, 다중 기준 정렬 편리 |
Stream.sorted() | Stream 데이터 | 기본 정렬 / Comparator | O(N log N) | 정렬 후 가공·출력 파이프라인 가능 |