CATEGORY

카테고리 (607)
AI (12)
Language & Specs (259)
FrameWork (34)
Library (19)
App (41)
Git (8)
Build & Dependency (2)
AWS (15)
DataBase (45)
OS (33)
Tool (16)
IT (120)
반응형
SEEMINGLY ONLINE

Seemingly
Online

이모저모 방방곡곡 두루두루 개발지식 저장소

RECENT POSTS

Language & Specs/Java

자바 Arrays.sort 내림차순 정렬 — int 배열과 오버플로 함정

반응형

자바에서 배열을 내림차순으로 정렬하는 방법은 배열 타입에 따라 다릅니다. Integer[]·String[] 같은 객체 배열Arrays.sort(arr, Collections.reverseOrder()) 한 줄이면 됩니다. 하지만 int[] 같은 기본형(primitive) 배열Comparator를 넘길 수 없어 이 방법이 컴파일 에러가 납니다. 이때는 스트림으로 박싱하거나, 오름차순으로 정렬한 뒤 뒤집어야 합니다. (기준: JDK 21에서 직접 실행 · 동작은 Java 8+ 공통)

1. 타입별 내림차순 정렬 — 한눈에

배열 타입 내림차순 방법
Integer[], String[] 등 객체 배열 Arrays.sort(arr, Collections.reverseOrder())
int[], double[] 등 기본형 배열 스트림 박싱 후 정렬, 또는 오름차순 정렬 후 뒤집기

핵심은 Arrays.sortComparator 오버로드가 객체 배열에만 있다는 점입니다. 기본형 배열용 Arrays.sort(int[])는 오름차순 전용이고 Comparator를 받는 형태가 없습니다.

2. 객체 배열(Integer[], String[]) 내림차순

Collections.reverseOrder()는 "자연 순서(natural ordering)의 반대"를 적용하는 Comparator를 돌려줍니다. 이걸 Arrays.sort의 두 번째 인자로 넘기면 끝입니다.

import java.util.*;

Integer[] boxed = {1, 26, 17, 25, 99};
Arrays.sort(boxed, Collections.reverseOrder());
System.out.println(Arrays.toString(boxed));
// [99, 26, 25, 17, 1]

String[] s = {"Apple", "Kiwi", "Orange", "Banana"};
Arrays.sort(s, Collections.reverseOrder());
System.out.println(Arrays.toString(s));
// [Orange, Kiwi, Banana, Apple]

출력은 위 주석 그대로입니다(JDK 21에서 실행 확인). 문자열은 사전 역순으로 정렬됩니다.

3. int[] 기본형 배열은 왜 안 되나

int[]Collections.reverseOrder()를 넘기면 아래처럼 컴파일 자체가 실패합니다.

int[] p = {3, 1, 2};
Arrays.sort(p, Collections.reverseOrder());
// error: no suitable method found for sort(int[],Comparator<Object>)
//   method Arrays.<T#1>sort(T#1[],Comparator<? super T#1>) is not applicable

Comparator는 객체에만 동작하는데 int는 객체가 아니기 때문입니다. 두 가지 우회법이 있습니다.

방법 A — 스트림으로 박싱해서 정렬

int[] prim = {1, 26, 17, 25, 99};
int[] desc = Arrays.stream(prim)
        .boxed()                              // IntStream -> Stream<Integer>
        .sorted(Comparator.reverseOrder())    // 내림차순
        .mapToInt(Integer::intValue)
        .toArray();
System.out.println(Arrays.toString(desc));
// [99, 26, 25, 17, 1]

방법 B — 오름차순 정렬 후 배열 뒤집기

박싱 비용이 부담되면, Arrays.sort로 오름차순 정렬한 뒤 앞뒤를 맞바꿔 뒤집습니다.

int[] p = {1, 26, 17, 25, 99};
Arrays.sort(p);                               // 오름차순
for (int i = 0; i < p.length / 2; i++) {
    int t = p[i];
    p[i] = p[p.length - 1 - i];
    p[p.length - 1 - i] = t;
}
System.out.println(Arrays.toString(p));
// [99, 26, 25, 17, 1]

4. 람다 (a, b) -> b - a 는 오버플로 함정이 있다

내림차순 Comparator를 (a, b) -> b - a로 쓰는 예제가 흔한데, 값이 크면 뺄셈이 int 범위를 넘어(overflow) 정렬이 깨집니다. Integer.MIN_VALUEInteger.MAX_VALUE가 섞이면 바로 드러납니다.

Integer[] ov = {Integer.MIN_VALUE, Integer.MAX_VALUE, 0};

Arrays.sort(ov, (x, y) -> y - x);            // ❌ 오버플로
System.out.println(Arrays.toString(ov));
// [-2147483648, 2147483647, 0]  ← 내림차순이 아님!

Arrays.sort(ov, (x, y) -> Integer.compare(y, x));  // ✅ 안전
System.out.println(Arrays.toString(ov));
// [2147483647, 0, -2147483648]

위 출력도 JDK 21에서 직접 확인한 결과입니다. y - xMAX - MIN이 오버플로해 음수가 되면서 순서가 뒤틀립니다. 반면 Integer.compare(y, x)는 뺄셈이 아니라 부호만 비교하므로 안전합니다.

⚠️ 비교 람다에서 b - a·a - b 같은 뺄셈은 쓰지 마세요. 항상 Integer.compare(또는 Comparator.reverseOrder()·Collections.reverseOrder())를 쓰면 오버플로 걱정이 없습니다.

자주 묻는 질문 (FAQ)

Q. Collections.reverseOrder() 와 Comparator.reverseOrder() 는 뭐가 다른가요?
둘 다 자연 순서의 역순 Comparator를 돌려주고, 결과는 같습니다. Collections.reverseOrder()는 예전부터 있던 것이고, Comparator.reverseOrder()는 Java 8에서 추가됐습니다. 스트림의 sorted()에는 보통 Comparator.reverseOrder()를 씁니다.

Q. char[] 나 double[] 도 int[] 와 같나요?
네. 모든 기본형 배열은 Arrays.sort에 Comparator를 넘길 수 없습니다. 박싱(스트림) 후 정렬하거나, 오름차순 정렬 후 뒤집는 방식을 씁니다.

Q. 정렬 안정성(stable)은 유지되나요?
객체 배열의 Arrays.sort는 안정 정렬(같은 값의 상대 순서 유지)입니다. Collections.reverseOrder()로 역순 정렬해도 안정성은 그대로 지켜집니다.

마무리

정리하면, 객체 배열은 Arrays.sort(arr, Collections.reverseOrder()), 기본형 배열은 스트림 박싱 또는 정렬 후 뒤집기입니다. 그리고 내림차순 람다에 b - a를 쓰는 습관만 Integer.compare(b, a)로 바꾸면 오버플로 버그를 원천 차단할 수 있습니다.


📚 참고 출처 (2026년 7월 20일 확인 · 코드는 JDK 21.0.1로 직접 실행)
· Java 21 API — Collections.reverseOrder()
· Java 21 API — Arrays.sort

반응형

COMMENTS