Skip to content

VOL 01 / CH 06 / LESSON 03

6.3 Array Copying, Utilities, and Varargs ​

Prerequisites: Array declaration, indexing, traversal, and methods

Estimated time: 30 minutes

You are ready to continue when: You can choose the appropriate copying method based on semantics, correctly use sorting and binary search, and define a strategy for handling empty input with varargs

Three scores are stored, and two more arrive. The existing array cannot change length; create a longer array and copy the existing values.

java
int[] oldScores = {85, 92, 78};
int[] newScores = java.util.Arrays.copyOf(oldScores, 5);
newScores[3] = 95;
newScores[4] = 88;

oldScores still references the old array with a length of 3, newScores references the new array with a length of 5. ArrayList will manage similar reallocation processes when capacity is insufficient, but the growth strategy is part of the implementation details, to be covered in the chapter on collections.

1. Five Copying Options, All Copying Component Values ​

Manual Loop ​

java
int[] source = {1, 2, 3};
int[] target = new int[source.length];
for (int index = 0; index < source.length; index++) {
    target[index] = source[index];
}

Manual looping is suitable when you also need to filter or transform during the copy. For simple, direct copying, the standard library is more clear.

clone ​

java
int[] copy = source.clone();

The clone method for arrays returns a new array of the same runtime component type and same length. It is a shallow copy.

Arrays.copyOf and copyOfRange ​

java
import java.util.Arrays;

int[] sameLength = Arrays.copyOf(source, source.length);
int[] longer = Arrays.copyOf(source, 5);   // [1, 2, 3, 0, 0]
int[] shorter = Arrays.copyOf(source, 2);  // [1, 2]
int[] slice = Arrays.copyOfRange(source, 1, 3); // [2, 3]

copyOf can truncate or pad with component default values. copyOfRange uses a left-closed, right-open interval [from, to); from must be within the valid range of the original array or exactly equal to its length. to can be greater than the original length, in which case the trailing elements are padded with default values, but cannot be less than from.

System.arraycopy ​

java
int[] source = {10, 20, 30, 40};
int[] target = new int[6];
System.arraycopy(source, 1, target, 2, 3);
// target: [0, 0, 20, 30, 40, 0]

The parameters are, in order, the source array, source start, target array, target start, and number of components. The source range must fit in the source array, and the destination range must fit in the destination array. Negative indices, negative counts, or going beyond either end will fail. Reference-array copies can throw ArrayStoreException when an element is incompatible with the destination’s runtime component type. Primitive arrays require the same component type; this method cannot widen int[] into long[].

If earlier reference elements fit but a later element does not, those earlier elements may already have been copied before ArrayStoreException is thrown. Failure does not roll back the operation. Copy into a separate array and validate it first when the original destination must be preserved.

The source and target can be the same array. Overlapping regions are handled with the semantics of "as if copied to a temporary array first":

java
int[] values = {1, 2, 3, 4, 5};
System.arraycopy(values, 0, values, 1, 4);
System.out.println(Arrays.toString(values));
// [1, 1, 2, 3, 4]

Do not use "which is always the fastest" as a criterion for selection. First choose the API based on whether you need a range, transformation, or change in length and overlapping copy. Only when performance becomes a measured bottleneck should you conduct benchmark tests on the target JVM and real data size.

2. Array Independence Does Not Equal Element Object Independence ​

java
StringBuilder[] first = {new StringBuilder("A")};
StringBuilder[] second = first.clone();

second[0].append("B");
System.out.println(first[0]); // AB

second[0] = new StringBuilder("C");
System.out.println(first[0]); // AB

first and second are two array objects, but the component initially holds the same StringBuilder reference. Modifying that object results in changes being observed on both sides; replacing second[0] only affects the second array's component.

"Deep copy" does not have a universal implementation for all objects. You need to first define object identity, sharing relationships, cyclic references, and whether immutable objects should be reused before implementing a copy strategy for your domain model.

3. Common Arrays Contracts ​

java
import java.util.Arrays;

int[] numbers = {42, 7, 15, 8, 23, 3};
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers));
// [3, 7, 8, 15, 23, 42]

int found = Arrays.binarySearch(numbers, 15);
System.out.println(found); // 3

int missing = Arrays.binarySearch(numbers, 9);
System.out.println(missing); // -4

binarySearch requires the search range to be sorted in the same order. Otherwise, the results have no meaningful interpretation. Return -(insertion point) - 1 when the key is not found, so -4 corresponds to insertion point 3. If there are duplicate keys, do not rely on which one is returned.

Common operations:

java
int[] filled = new int[4];
Arrays.fill(filled, 7); // [7, 7, 7, 7]

int[] left = {1, 2, 3};
int[] right = {1, 4, 3};
System.out.println(Arrays.equals(left, right)); // false
System.out.println(Arrays.mismatch(left, right)); // 1
MethodResultImportant Boundary
sort(array)In-place natural order sortingModifies the original array
binarySearch(array, key)Index or negative insertion point encodingMust be sorted in the same order before searching
fill(array, value)Fills with the same component valueEvery filled slot receives the same reference
equals(a, b)Compares one-dimensional array componentsNested arrays typically use deepEquals
mismatch(a, b)First differing position, -1 if no differencesAvailable since Java 9
toString(array)Readable text for one-dimensional arraysNested arrays use deepToString

When directly concatenating array objects, common [I@... types of strings are encountered. This is the string representation of the array object inheritance, including the type and identity hash; it is not the array content and cannot be treated as a memory address promise. Use Arrays.toString for output components.

4. Varargs Parameters Are Arrays Inside the Method ​

java
static double average(int... numbers) {
    if (numbers.length == 0) {
        throw new IllegalArgumentException("no numbers");
    }
    long sum = 0L;
    for (int number : numbers) {
        sum = Math.addExact(sum, number);
    }
    return (double) sum / numbers.length;
}

Calling Convention:

java
average(85, 92, 78);
average(new int[]{90, 95});
// average(); // Under this contract, throws IllegalArgumentException

Rules:

  1. A method declaration can have at most one varargs parameter.
  2. Varargs parameters must be placed at the end of the parameter list.
  3. When calling, you can pass 0, 1, or multiple actual parameters, or directly pass a compatible array.
  4. int... and int[] cannot form two overloads in the method signature, as they correspond to the same parameter type.

average((int[]) null) will pass null as the entire array parameter, and then accessing length will fail. Do not use null to represent "no varargs parameter"; instead, simply do not pass any parameters and let the method explicitly handle a length 0 array.

If both show(int...) and show(String...) are overloaded, calling show(null) will result in an overload ambiguity; type conversion can eliminate the ambiguity, but a better API would often avoid this pair of overloads.

Professional Quick Reference ​

TaskPreferredReason
Full Shallow Copyclone() or Arrays.copyOfDirectly create a new array
Change Copy LengthArrays.copyOfExplicitly truncate or pad with default values
Copy a SubarrayArrays.copyOfRangeReturns a new array
Copy to an Existing Target LocationSystem.arraycopyControls source and target ranges and supports overlapping
Copy with TransformationIndex LoopEach component can execute custom logic
Search a Sorted ArrayArrays.binarySearchRequires that the preconditions for sorting are met

Before Moving On ​

Predict the results of copyOf extension, truncation, and arraycopy overlap copy separately, and draw the shared object of the referenced array shallow copy. When binary search fails to find a value, manually convert the negative return value back to the insertion point; for variable arguments, test all three scenarios: 0 arguments, explicit array, and the forcibly converted null.

→ Next: Multidimensional Arrays

API Entry: Java 17 Arrays Documentation, Java 17 System.arraycopy.

Built with VitePress | Software Systems Atlas