HOWTO · Java
How to Create a Subarray in Java
Learn how to copy a contiguous range into a new Java array with Arrays.copyOfRange, System.arraycopy, a loop, or the Stream API.
On this page
A subarray is a contiguous range copied into a separate array. Java arrays use zero-based indexes: the start index is included, and the end index marks the position after the last copied element. These examples use indexes 1 through 3 from the source array.
What a subarray means in Java
Copying a range creates a new array; it does not create a view into the original. Changing an element in a copied int[] therefore does not change the source. For arrays of objects, the new array contains the same object references, so changing an object itself can still be visible through either array.
The usual range notation is [start, end): start is included and end is excluded. For a source with nine elements, indexes run from 0 to 8. A range from 2 to 5 contains three elements. Keep this convention in mind when translating a desired element count into an end index: end is start + length.
Create a subarray with Arrays.copyOfRange
Arrays.copyOfRange is a concise choice when you want a newly allocated array. Pass the source, inclusive start, and exclusive end, in that order. Run this example:
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]
The result is a separate array containing source indexes 1, 2, and 3. The end index is not copied. An end beyond the source length is permitted and pads the result with the component type’s default value (0 for int, null for a reference type). The start must be within the source or at its length, and the end cannot precede the start. If you need an end beyond the source to be an error instead, validate it before calling the method.
Create a subarray with System.arraycopy
Use System.arraycopy when you need to choose the destination array or its insertion position. Its five arguments are source array, source position, destination array, destination position, and number of elements. The last argument is a count, not an end index; the destination must have room from its destination position for that many elements.
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));
}
}
Here the copied range ends at start + length, which is 4 and is excluded. Allocate the destination using the intended copy length. Java checks the positions and lengths; incompatible reference-array element types can also cause an array-store error.
Create a subarray with a loop
A loop makes the destination offset explicit and lets you inspect or transform each element while copying. For the range [start, end), destination index i - start begins at zero and advances with the source index.
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));
}
}
The loop assumes the indexes describe a valid range in the source. Check them before allocating if they come from user input. Unlike Arrays.copyOfRange, a loop does not automatically pad when the requested end exceeds the source; indexing beyond the source fails. A loop is useful when copying also involves a condition, conversion, or other custom rule.
Create a subarray with the Stream API
For an int[], IntStream.range(start, end) produces the indexes from the inclusive start up to, but not including, the end. Map each index to its source value, then collect those values into a new primitive array with 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));
}
}
This has the same range convention as the earlier examples. The indexes produced by the stream still need to be valid for the source array. Use this approach when you already want to express the selection as an index pipeline; a stream does not by itself make range validation unnecessary.
Choose a method for your use case
Choose Arrays.copyOfRange for the direct operation of allocating and copying a range, especially when its end-padding behavior is useful. Choose System.arraycopy when you already have a destination or need to place the copied values at a nonzero destination position. Choose a loop when the copy needs custom per-element logic. Choose the Stream API when composing index-based transformations makes the code easier to follow.
Arrays.copyOfRange, the loop, and the Stream API example each allocate a new array. System.arraycopy copies into the destination array you provide, so it creates a new container only when you allocate one for that purpose. For a primitive array, values are copied. For an object array, references are copied rather than the referenced objects themselves. Select the method based on the required range behavior, destination control, and additional processing; these examples make no performance comparison.