HOWTO · Java
Java에서 하위 배열 만들기
이 튜토리얼은 Java의 다른 배열에서 하위 배열을 만드는 방법을 보여줍니다.
이 페이지의 내용
하위 배열은 연속된 범위를 별도의 배열로 복사한 것입니다. Java 배열의 인덱스는 0부터 시작합니다. 시작 인덱스는 범위에 포함되고, 끝 인덱스는 마지막으로 복사한 요소 다음 위치를 가리킵니다. 이 예제에서는 원본 배열의 인덱스 1부터 3까지를 사용합니다.
Java에서 하위 배열이란
범위를 복사하면 새 배열이 만들어지며, 원본 배열을 바라보는 뷰가 만들어지는 것은 아닙니다. 따라서 복사한 int[]의 요소를 바꿔도 원본 배열은 바뀌지 않습니다. 객체 배열의 경우 새 배열에 원본과 동일한 객체 참조가 들어 있으므로, 객체 자체를 변경하면 어느 배열을 통해서든 변경된 내용이 보일 수 있습니다.
일반적인 범위 표기법은 [start, end)입니다. start는 포함되고 end는 제외됩니다. 요소가 아홉 개인 원본 배열의 인덱스는 0부터 8까지입니다. 2부터 5까지의 범위에는 요소가 세 개 들어 있습니다. 원하는 요소 수를 끝 인덱스로 바꿀 때 이 규칙을 기억하세요. end는 start + length입니다.
Arrays.copyOfRange로 하위 배열 만들기
새 배열을 할당해 범위를 복사하려면 Arrays.copyOfRange를 간결하게 사용할 수 있습니다. 원본 배열, 시작 인덱스(포함), 끝 인덱스(제외) 순으로 전달합니다. 다음 예제를 실행해 보세요.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.
import java.util.Arrays;
public class SubarrayExample {
public static void main(String[] args) {
int[] source = {10, 20, 30, 40, 50, 60};
int[] part = Arrays.copyOfRange(source, 1, 4);
System.out.println(Arrays.toString(part));
}
}
[20, 30, 40]
결과는 원본 배열의 인덱스 1, 2, 3을 포함하는 별도의 배열입니다. 끝 인덱스에 해당하는 요소는 복사되지 않습니다. 원본 배열 길이보다 큰 끝 인덱스도 허용되며, 결과 배열의 나머지 요소는 구성 요소 타입의 기본값으로 채워집니다(int는 0, 참조 타입은 null). 시작 인덱스는 원본 배열의 유효한 인덱스이거나 배열 길이와 같아야 하며, 끝 인덱스는 시작 인덱스보다 작을 수 없습니다. 원본 배열 길이를 넘는 끝 인덱스를 오류로 처리해야 한다면 메서드를 호출하기 전에 검사하세요.
System.arraycopy로 하위 배열 만들기
대상 배열이나 값을 넣을 위치를 직접 정해야 한다면 System.arraycopy를 사용하세요. 인수 다섯 개는 원본 배열, 원본 위치, 대상 배열, 대상 위치, 복사할 요소 수입니다. 마지막 인수는 끝 인덱스가 아니라 개수입니다. 대상 배열에는 대상 위치부터 그 개수만큼 요소를 넣을 공간이 있어야 합니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.
import java.util.Arrays;
public class SubarrayWithArraycopy {
public static void main(String[] args) {
int[] source = {10, 20, 30, 40, 50, 60};
int start = 1;
int length = 3;
int[] part = new int[length];
System.arraycopy(source, start, part, 0, length);
System.out.println(Arrays.toString(part));
}
}
여기서 복사 범위의 끝은 start + length이며, 그 값은 4이고 범위에서 제외됩니다. 복사할 길이에 맞춰 대상 배열을 할당하세요. Java는 위치와 길이를 검사합니다. 참조 배열의 요소 타입이 호환되지 않으면 배열 저장 오류가 발생할 수도 있습니다.
반복문으로 하위 배열 만들기
반복문을 사용하면 대상 배열의 오프셋을 명확히 지정할 수 있고, 복사하면서 각 요소를 살펴보거나 변환할 수도 있습니다. [start, end) 범위에서 대상 인덱스 i - start는 0에서 시작해 원본 인덱스와 함께 증가합니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.
import java.util.Arrays;
public class SubarrayWithLoop {
public static void main(String[] args) {
int[] source = {10, 20, 30, 40, 50, 60};
int start = 1;
int end = 4;
int[] part = new int[end - start];
for (int i = start; i < end; i++) {
part[i - start] = source[i];
}
System.out.println(Arrays.toString(part));
}
}
이 반복문은 인덱스가 원본 배열의 유효한 범위를 나타낸다고 가정합니다. 사용자 입력에서 인덱스를 받는다면 배열을 할당하기 전에 검사하세요. Arrays.copyOfRange와 달리 반복문은 요청한 끝 인덱스가 원본 배열 길이를 넘어도 자동으로 값을 채우지 않습니다. 배열 범위를 벗어난 인덱스에 접근하면 실패합니다. 복사하면서 조건을 적용하거나 값을 변환하는 등 사용자 지정 처리가 필요할 때 반복문이 유용합니다.
Stream API로 하위 배열 만들기
int[]에서는 IntStream.range(start, end)가 시작 인덱스는 포함하고 끝 인덱스는 제외하는 범위의 인덱스를 생성합니다. 각 인덱스를 원본 배열의 값으로 매핑한 다음 toArray()로 값을 새 기본형 배열에 모읍니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.
import java.util.Arrays;
import java.util.stream.IntStream;
public class SubarrayWithStream {
public static void main(String[] args) {
int[] source = {10, 20, 30, 40, 50, 60};
int[] part = IntStream.range(1, 4)
.map(i -> source[i])
.toArray();
System.out.println(Arrays.toString(part));
}
}
앞서 나온 예제와 범위 규칙은 같습니다. 스트림이 생성한 인덱스도 원본 배열에서 유효해야 합니다. 인덱스 기반 파이프라인으로 선택 과정을 표현하려는 경우 이 방식을 사용하세요. 스트림을 사용해도 범위 검사가 불필요해지는 것은 아닙니다.
사용 사례에 맞는 방법 선택하기
범위를 새 배열에 할당해 복사하는 직접적인 작업에는 Arrays.copyOfRange를 선택하세요. 특히 끝 인덱스가 원본 배열 길이를 넘어도 결과를 채우는 동작이 유용할 때 적합합니다. 이미 대상 배열이 있거나 복사한 값을 0이 아닌 대상 위치에 넣어야 한다면 System.arraycopy를 선택하세요. 요소마다 사용자 지정 로직을 적용해야 한다면 반복문을 사용하고, 인덱스 기반 변환을 조합하면 코드를 더 쉽게 이해할 수 있는 경우에는 Stream API를 사용하세요.
Arrays.copyOfRange, 반복문, Stream API 예제는 각각 새 배열을 할당합니다. System.arraycopy는 제공한 대상 배열에 복사하므로, 새 컨테이너는 그 목적으로 배열을 할당할 때만 만들어집니다. 기본형 배열에서는 값이 복사됩니다. 객체 배열에서는 객체 자체가 아니라 객체에 대한 참조가 복사됩니다. 필요한 범위 동작, 대상 배열 제어, 추가 처리 여부를 기준으로 방법을 선택하세요. 이 예제들은 성능을 비교하지 않습니다.