본문으로 건너뛰기

5.4 Arrays 유틸리티 클래스 (Arrays Utility Class)

자바는 배열을 다룰 때 개발자가 직접 반복문을 작성하지 않고도 출력, 복사, 정렬, 검색 등을 손쉽게 처리할 수 있도록 java.util.Arrays 클래스를 제공합니다. 이 클래스의 모든 메서드는 static이므로 객체 생성 없이 바로 사용합니다.

1. 배열 출력: Arrays.toString() / Arrays.deepToString()

배열을 println()으로 직접 출력하면 의미 없는 메모리 주소값이 나옵니다.

import java.util.Arrays;

int[] arr = {10, 20, 30, 40, 50};

System.out.println(arr); // [I@7ef88735 (주소값, 의미 없음)
System.out.println(Arrays.toString(arr)); // [10, 20, 30, 40, 50]

2차원 배열: deepToString()

int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};

System.out.println(Arrays.toString(matrix)); // [[I@..., [I@..., ...] (잘못된 방법)
System.out.println(Arrays.deepToString(matrix)); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

2. 배열 정렬: Arrays.sort()

배열 요소를 오름차순 으로 정렬합니다. 내부적으로 Dual-Pivot Quicksort 알고리즘을 사용합니다.

기본 정렬 (오름차순)

int[] numbers = {5, 3, 8, 1, 9, 2, 7, 4, 6};
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers));
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

String[] names = {"Charlie", "Alice", "Bob", "David"};
Arrays.sort(names);
System.out.println(Arrays.toString(names));
// [Alice, Bob, Charlie, David]

부분 정렬

int[] arr = {5, 3, 8, 1, 9, 2, 7};
Arrays.sort(arr, 1, 5); // 인덱스 1~4(5 미만)만 정렬
System.out.println(Arrays.toString(arr));
// [5, 1, 3, 8, 9, 2, 7] - 1번~4번 인덱스만 정렬됨

내림차순 정렬 (Comparator 사용)

기본형 배열은 Comparator를 직접 사용할 수 없으므로 Integer[]로 변환하거나, Java 8+에서는 IntStream을 활용합니다.

// Integer[] 사용 (박싱)
Integer[] nums = {5, 3, 8, 1, 9};
Arrays.sort(nums, Comparator.reverseOrder()); // 내림차순
System.out.println(Arrays.toString(nums)); // [9, 8, 5, 3, 1]

// String 배열 내림차순
String[] words = {"banana", "apple", "cherry"};
Arrays.sort(words, Comparator.reverseOrder());
System.out.println(Arrays.toString(words)); // [cherry, banana, apple]

// 길이순 정렬
Arrays.sort(words, Comparator.comparingInt(String::length));
System.out.println(Arrays.toString(words)); // [apple, banana, cherry]

3. 이진 탐색: Arrays.binarySearch()

정렬된 배열에서 특정 값을 O(log n) 시간에 검색합니다.

반드시 정렬 후 사용

binarySearch()는 배열이 오름차순 정렬된 상태 에서만 정확한 결과를 반환합니다.

int[] sorted = {10, 20, 30, 40, 50, 60, 70};
Arrays.sort(sorted); // 이미 정렬되어 있지만 습관적으로 확인

int idx = Arrays.binarySearch(sorted, 40);
System.out.println("40의 위치: " + idx); // 3

int notFound = Arrays.binarySearch(sorted, 35);
System.out.println("35의 위치: " + notFound); // 음수 (없음)

반환 값:

  • 값이 존재하면: 해당 인덱스 (0 이상)
  • 값이 없으면: -(삽입 위치) - 1 (음수)
// String 배열에도 사용 가능
String[] names = {"Alice", "Bob", "Charlie", "David", "Eve"};
Arrays.sort(names);

int pos = Arrays.binarySearch(names, "Charlie");
System.out.println("Charlie의 위치: " + pos); // 2

int notFound = Arrays.binarySearch(names, "Frank");
System.out.println("Frank의 위치: " + notFound); // 음수 (-6)

4. 배열 채우기: Arrays.fill()

배열의 모든 요소(또는 일부)를 특정 값으로 채웁니다.

int[] arr = new int[5];

// 전체 채우기
Arrays.fill(arr, 7);
System.out.println(Arrays.toString(arr)); // [7, 7, 7, 7, 7]

// 부분 채우기 (인덱스 1~3)
Arrays.fill(arr, 1, 4, 99);
System.out.println(Arrays.toString(arr)); // [7, 99, 99, 99, 7]

// 초기화 용도
int[] board = new int[10];
Arrays.fill(board, -1); // -1로 초기화 (미방문 표시 등)
System.out.println(Arrays.toString(board)); // [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]

5. 배열 복사: Arrays.copyOf() / Arrays.copyOfRange()

int[] original = {1, 2, 3, 4, 5};

// 동일 크기 복사
int[] copy1 = Arrays.copyOf(original, original.length);
System.out.println(Arrays.toString(copy1)); // [1, 2, 3, 4, 5]

// 더 큰 배열로 복사 (나머지는 기본값 0)
int[] copy2 = Arrays.copyOf(original, 8);
System.out.println(Arrays.toString(copy2)); // [1, 2, 3, 4, 5, 0, 0, 0]

// 더 작은 배열로 복사 (잘림)
int[] copy3 = Arrays.copyOf(original, 3);
System.out.println(Arrays.toString(copy3)); // [1, 2, 3]

// 범위 지정 복사 (인덱스 1 이상 4 미만)
int[] copy4 = Arrays.copyOfRange(original, 1, 4);
System.out.println(Arrays.toString(copy4)); // [2, 3, 4]

// 범위가 배열 길이를 초과하면 0으로 채움
int[] copy5 = Arrays.copyOfRange(original, 3, 8);
System.out.println(Arrays.toString(copy5)); // [4, 5, 0, 0, 0]

6. 배열 비교: Arrays.equals() / Arrays.deepEquals()

int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
int[] c = {1, 2, 4};

System.out.println(a == b); // false (다른 객체)
System.out.println(Arrays.equals(a, b)); // true (내용이 같음)
System.out.println(Arrays.equals(a, c)); // false (내용이 다름)

// 2차원 배열 비교
int[][] m1 = {{1, 2}, {3, 4}};
int[][] m2 = {{1, 2}, {3, 4}};

System.out.println(Arrays.equals(m1, m2)); // false (얕은 비교)
System.out.println(Arrays.deepEquals(m1, m2)); // true (깊은 비교)

7. 배열 → List 변환: Arrays.asList()

배열을 List로 변환하여 컬렉션 API를 사용할 수 있습니다.

import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

String[] arr = {"사과", "바나나", "오렌지"};

// 고정 크기 List (add/remove 불가!)
List<String> fixedList = Arrays.asList(arr);
System.out.println(fixedList); // [사과, 바나나, 오렌지]

// fixedList.add("포도"); // UnsupportedOperationException!

// 수정 가능한 List로 만들려면 새 ArrayList에 복사
List<String> mutableList = new ArrayList<>(Arrays.asList(arr));
mutableList.add("포도");
System.out.println(mutableList); // [사과, 바나나, 오렌지, 포도]
Arrays.asList() 주의사항

Arrays.asList()가 반환하는 List는 고정 크기 입니다. set()(값 변경)은 가능하지만 add(), remove()는 불가합니다. 또한 기본형 배열(int[])은 List<int[]>가 되므로 Integer[]를 사용해야 합니다.

int[] primitives = {1, 2, 3};
List<int[]> wrong = Arrays.asList(primitives); // List의 원소가 int[] 배열 1개!

Integer[] boxed = {1, 2, 3};
List<Integer> correct = Arrays.asList(boxed); // [1, 2, 3]

8. 배열 → Stream 변환: Arrays.stream()

Java 8+에서 배열을 스트림으로 변환하여 함수형 처리가 가능합니다.

import java.util.Arrays;

int[] numbers = {3, 1, 4, 1, 5, 9, 2, 6};

// 합계
int sum = Arrays.stream(numbers).sum();
System.out.println("합계: " + sum); // 31

// 최대/최소
int max = Arrays.stream(numbers).max().getAsInt();
int min = Arrays.stream(numbers).min().getAsInt();
System.out.println("최대: " + max + ", 최소: " + min); // 최대: 9, 최소: 1

// 평균
double avg = Arrays.stream(numbers).average().getAsDouble();
System.out.println("평균: " + avg); // 3.875

// 필터링 후 배열로 변환
int[] evens = Arrays.stream(numbers).filter(n -> n % 2 == 0).toArray();
System.out.println("짝수만: " + Arrays.toString(evens)); // [4, 2, 6]

// 각 요소 변환 (2배)
int[] doubled = Arrays.stream(numbers).map(n -> n * 2).toArray();
System.out.println("2배: " + Arrays.toString(doubled)); // [6, 2, 8, 2, 10, 18, 4, 12]

9. Collections 유틸리티 간단 소개

java.util.Collections는 List에 사용하는 유틸리티 클래스입니다. 배열을 List로 변환 후 활용합니다.

import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

List<Integer> list = new ArrayList<>(Arrays.asList(5, 3, 8, 1, 9, 2));

// 정렬
Collections.sort(list);
System.out.println(list); // [1, 2, 3, 5, 8, 9]

// 최대/최소
System.out.println(Collections.max(list)); // 9
System.out.println(Collections.min(list)); // 1

// 무작위 셔플
Collections.shuffle(list);
System.out.println(list); // 임의 순서로 섞임

// 역순
Collections.reverse(list);
System.out.println(list); // 현재 순서의 역순

// 빈도 수
List<String> words = Arrays.asList("apple", "banana", "apple", "cherry", "apple");
System.out.println(Collections.frequency(words, "apple")); // 3

10. 실전 예제: 학생 이름 배열 정렬 및 이진 탐색

import java.util.Arrays;
import java.util.Scanner;

public class StudentSearch {
public static void main(String[] args) {
String[] students = {
"홍길동", "김민준", "이서연", "박지훈", "최수아",
"정도윤", "강하은", "윤시우", "임지아", "오준서"
};

System.out.println("원본 명단:");
System.out.println(Arrays.toString(students));

// 오름차순 정렬
Arrays.sort(students);
System.out.println("\n정렬된 명단:");
System.out.println(Arrays.toString(students));

// 이진 탐색으로 학생 검색
Scanner scanner = new Scanner(System.in);
System.out.print("\n검색할 학생 이름: ");
String target = scanner.next();

int index = Arrays.binarySearch(students, target);

if (index >= 0) {
System.out.println(target + "님은 " + (index + 1) + "번째에 있습니다.");
} else {
System.out.println(target + "님은 명단에 없습니다.");
// 삽입 위치 계산: -(index + 1)
int insertPos = -(index + 1);
System.out.println("추가하려면 " + (insertPos + 1) + "번째에 삽입하세요.");
}

// 추가 통계
System.out.println("\n이름 길이 통계:");
int totalLen = 0;
for (String s : students) totalLen += s.length();
System.out.printf("평균 이름 길이: %.1f자%n", (double) totalLen / students.length);

int longestIdx = 0;
for (int i = 1; i < students.length; i++) {
if (students[i].length() > students[longestIdx].length()) {
longestIdx = i;
}
}
System.out.println("가장 긴 이름: " + students[longestIdx]);

scanner.close();
}
}

실행 예시:

원본 명단:
[홍길동, 김민준, 이서연, 박지훈, 최수아, 정도윤, 강하은, 윤시우, 임지아, 오준서]

정렬된 명단:
[강하은, 김민준, 박지훈, 오준서, 윤시우, 이서연, 임지아, 정도윤, 최수아, 홍길동]

검색할 학생 이름: 이서연
이서연님은 6번째에 있습니다.

11. Arrays 메서드 빠른 참조표

메서드설명예시
toString(arr)1차원 배열을 문자열로[1, 2, 3]
deepToString(arr)다차원 배열을 문자열로[[1, 2], [3, 4]]
sort(arr)오름차순 정렬-
sort(arr, from, to)부분 정렬-
sort(arr, comparator)커스텀 정렬-
binarySearch(arr, key)이진 탐색인덱스 또는 음수
fill(arr, val)전체 채우기-
fill(arr, from, to, val)부분 채우기-
copyOf(arr, len)길이 지정 복사-
copyOfRange(arr, from, to)범위 복사-
equals(a, b)1차원 배열 비교true/false
deepEquals(a, b)다차원 배열 비교true/false
asList(arr)배열 → 고정 List-
stream(arr)배열 → Stream-
고수 팁

실무에서 Arrays 활용 패턴:

  1. 디버깅: System.out.println(Arrays.toString(arr))으로 배열 내용을 빠르게 확인
  2. 배열 확장: Arrays.copyOf(arr, arr.length * 2)로 배열을 2배 크기로 늘리기
  3. 방어적 복사: 메서드에서 배열을 반환할 때 return arr.clone()으로 원본 보호
  4. equals 대체: 단위 테스트에서 Arrays.equals(expected, actual)로 배열 검증
// 방어적 복사 예시
public class SafeArray {
private int[] data;

public SafeArray(int[] input) {
this.data = input.clone(); // 외부 배열 변경 방어
}

public int[] getData() {
return data.clone(); // 내부 배열 노출 방어
}
}