알고리즘 문제를 풀다 보면 결과값의 크기를 미리 알 수 없어 동적 배열인 ArrayList에 데이터를 담아두는 경우가 많습니다. 하지만 문제의 반환 타입(Return Type)이 기본형 배열인 int[]로 고정되어 있다면 타입 불일치 문제가 발생합니다.
public static int[] solution(int[] num_list, int n) {
ArrayList<Integer> list = new ArrayList<>();
for(int i = 0; i < num_list.length; i += n) {
list.add(num_list[i]);
}
// 컴파일 에러: ArrayList<Integer>를 int[]로 바로 반환할 수 없음
return list;
}
ArrayList의 toArray() 메서드를 사용하더라도 Integer[]나 Object[]로만 변환될 뿐, 원시 타입(Primitive Type)인 int[]로는 바로 변환되지 않습니다.
이때 자바 8부터 도입된 Stream API를 사용하면 이 형변환 과정을 단 한 줄의 코드로 우아하게 처리할 수 있습니다.
`return list.stream().mapToInt(i -> i).toArray();`
이 코드가 내부적으로 어떻게 동작하여 ArrayList<Integer>를 int[]로 변환하는지 3단계로 나누어 살펴보겠습니다.
.stream() : 객체 스트림 생성가장 먼저 컬렉션(ArrayList)을 스트림으로 변환합니다.
list.stream()을 호출하면 ArrayList에 담긴 데이터들을 순차적으로 처리할 수 있는 Stream<Integer> 타입의 객체 스트림이 생성됩니다.Integer 객체 형태로 존재합니다..mapToInt(i -> i) : IntStream 변환 및 오토 언박싱 (Auto-Unboxing)스트림의 요소를 기본형 스트림으로 변환하는 핵심 단계입니다.
mapToInt() 메서드는 기존의 Stream<Integer>를 원시 타입 스트림인 IntStream으로 매핑(Mapping)합니다.i -> i는 들어온 Integer 객체를 그대로 반환하라는 의미입니다.Integer 객체에서 기본형 int 값을 추출하는 오토 언박싱(Auto-Unboxing)을 수행합니다.Integer::intValue를 사용하면 언박싱 과정을 더 명시적으로 표현할 수 있습니다.).toArray() : 배열로 수집 (종단 연산)변환된 스트림 데이터를 최종적으로 배열로 묶어냅니다.
IntStream을 통과한 순수 int 값들을 모아, 새로운 int[] 배열을 메모리에 할당하고 값을 복사한 뒤 이를 반환합니다.list.stream().mapToInt(i -> i).toArray()는 단순한 마법이 아니라, 스트림 생성 ➔ 객체의 언박싱 매핑 ➔ 원시 타입 배열로의 수집이라는 명확한 자바의 동작 방식을 따르고 있습니다.
반복문을 직접 작성하여 배열로 옮겨 담는 것(for문 사용)보다 성능 오버헤드는 아주 미세하게 존재할 수 있으나, 가독성과 유지보수성이 압도적으로 뛰어나기 때문에 실무와 코딩 테스트에서 가장 널리 권장되는 방식입니다.