Java Arrays Class

Java’s built-in array type is deliberately bare-bones: it stores a fixed-size sequence of elements and gives you almost no methods to work with. The java.util.Arrays class fills that gap. It is a utility class full of static methods for sorting, searching, comparing, filling, copying, and printing arrays, so you rarely need to hand-write these operations yourself. Understanding it well means you spend less time reinventing loops and more time writing the logic that actually matters.

This lesson covers the most important methods on java.util.Arrays, how they behave internally, and the mistakes beginners commonly make when using them.

Overview / How it works

Arrays lives in the java.util package, so you must import it with import java.util.Arrays; before using it. It is a final class with a private constructor, meaning you can never instantiate it—every method is called directly on the class name, like Arrays.sort(myArray). This is the same design pattern used by Math and Collections: a stateless bag of static helper methods.

Internally, most Arrays methods operate directly on the array’s underlying memory block. Java arrays are objects stored on the heap with a fixed length determined at creation time and a contiguous block of memory holding the elements. When you call Arrays.sort(arr), the JVM does not create a new array—it rearranges the elements in place inside that same memory block. Methods like Arrays.copyOf, on the other hand, allocate a brand-new array and copy elements into it, leaving the original untouched. Knowing which category a method falls into (mutates in place vs. returns a new array) is essential to avoid subtle bugs.

Arrays is heavily overloaded: nearly every method has a version for int[], double[], long[], char[], boolean[], and Object[] (which covers String[], custom classes, etc.). The compiler picks the right overload automatically based on the array’s declared type.

Syntax

There is no single “syntax” for a utility class—instead you call individual static methods. The general form is:

Arrays.methodName(array, [otherArguments...]);
Method Purpose
Arrays.sort(arr) Sorts the array in place, ascending order
Arrays.sort(arr, comparator) Sorts an object array using a custom order
Arrays.binarySearch(arr, key) Finds the index of key in a sorted array
Arrays.fill(arr, value) Sets every element to value
Arrays.copyOf(arr, newLength) Returns a new array, truncated or zero/null-padded
Arrays.copyOfRange(arr, from, to) Returns a new array with elements [from, to)
Arrays.equals(a, b) Compares two 1D arrays element by element
Arrays.deepEquals(a, b) Compares nested (multi-dimensional) arrays recursively
Arrays.toString(arr) Returns a readable [a, b, c] style string
Arrays.deepToString(arr) Readable string for nested arrays
Arrays.asList(arr) Wraps an array in a fixed-size List view

Examples

Example 1: Sorting and printing

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] numbers = {5, 3, 8, 1, 9, 2};
        System.out.println("Original: " + Arrays.toString(numbers));
        Arrays.sort(numbers);
        System.out.println("Sorted: " + Arrays.toString(numbers));
    }
}

Output:

Original: [5, 3, 8, 1, 9, 2]
Sorted: [1, 2, 3, 5, 8, 9]

Arrays.sort uses a dual-pivot quicksort for primitive arrays (fast, in-place, but not stable) and a stable, adaptive merge sort (TimSort) for object arrays, because sorting objects sometimes needs to preserve the original relative order of equal elements. Arrays.toString is what you should always use to print array contents—printing the array variable directly does not work as you’d expect (see Common Mistakes below).

Example 2: Searching, filling, and copying

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] scores = {40, 55, 60, 75, 90};

        int index = Arrays.binarySearch(scores, 60);
        System.out.println("Index of 60: " + index);

        int[] filled = new int[5];
        Arrays.fill(filled, 7);
        System.out.println("Filled: " + Arrays.toString(filled));

        int[] extended = Arrays.copyOf(scores, 7);
        System.out.println("Copied with extra: " + Arrays.toString(extended));

        int[] range = Arrays.copyOfRange(scores, 1, 4);
        System.out.println("Range [1,4): " + Arrays.toString(range));
    }
}

Output:

Index of 60: 2
Filled: [7, 7, 7, 7, 7]
Copied with extra: [40, 55, 60, 75, 90, 0, 0]
Range [1,4): [55, 60, 75]

binarySearch requires a sorted array—scores already was, so it correctly finds 60 at index 2. copyOf to a larger length pads the new slots with the default value (0 for int, null for objects). copyOfRange follows the same half-open convention as String.substring: the end index is exclusive.

Example 3: Custom sort order and multi-dimensional arrays

import java.util.Arrays;
import java.util.Comparator;

public class Main {
    public static void main(String[] args) {
        String[] names = {"Charlie", "Alice", "Bob"};
        Arrays.sort(names);
        System.out.println("Alphabetical: " + Arrays.toString(names));

        Arrays.sort(names, Comparator.reverseOrder());
        System.out.println("Reverse: " + Arrays.toString(names));

        int[][] grid = {{1, 2}, {3, 4}};
        int[][] gridCopy = {{1, 2}, {3, 4}};
        System.out.println("equals: " + Arrays.equals(grid, gridCopy));
        System.out.println("deepEquals: " + Arrays.deepEquals(grid, gridCopy));
        System.out.println("deepToString: " + Arrays.deepToString(grid));
    }
}

Output:

Alphabetical: [Alice, Bob, Charlie]
Reverse: [Charlie, Bob, Alice]
equals: false
deepEquals: true
deepToString: [[1, 2], [3, 4]]

Note that Arrays.equals returns false for the two grids: a 2D array in Java is really an array of array references, so equals only compares those references (which point to different inner arrays), not their contents. deepEquals recurses into nested arrays and compares actual values, and deepToString is the only way to print a 2D array’s contents correctly.

How it works step by step (under the hood)

  • Primitive sort: for int[], double[], etc., Arrays.sort runs a dual-pivot quicksort variant directly over the array’s memory, swapping elements in place with O(n log n) average time and O(1) extra space.
  • Object sort: for Object[] (including String[]), Arrays.sort uses a stable merge sort (TimSort), which needs O(n) auxiliary space but guarantees elements considered “equal” by the comparator keep their original relative order.
  • binarySearch: repeatedly halves the search range, comparing the middle element to the key. This only works correctly if the array is already sorted in ascending order—the algorithm has no way to detect an unsorted array and will silently return a wrong or misleading result.
  • copyOf / copyOfRange: internally call System.arraycopy, a native method that performs a fast, low-level memory copy rather than a Java loop, which is why these methods are much faster than manually copying elements one by one.
  • asList: wraps the existing array in a List object without copying data; the returned list is backed directly by the array, so changes to one are visible through the other.

Common Mistakes

Mistake 1: Printing an array directly instead of using Arrays.toString

Arrays do not override toString(), so printing one directly prints its type and memory-derived hash code, not its contents.

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] data = {10, 20, 30};
        System.out.println(data);
    }
}

Output (exact hash varies each run):

[I@1540e19d

The fix is to always wrap the array with Arrays.toString (or Arrays.deepToString for nested arrays):

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] data = {10, 20, 30};
        System.out.println(Arrays.toString(data));
    }
}

Output:

[10, 20, 30]

Mistake 2: Trying to add or remove elements from Arrays.asList

Arrays.asList returns a fixed-size List view backed by the array. Structural changes like add or remove are not supported because that would require resizing the underlying array.

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

public class Main {
    public static void main(String[] args) {
        Integer[] nums = {1, 2, 3};
        List list = Arrays.asList(nums);
        try {
            list.add(4);
        } catch (UnsupportedOperationException e) {
            System.out.println("Error: " + e);
        }
    }
}

Output:

Error: java.lang.UnsupportedOperationException

If you need a resizable list from an array, copy the fixed-size view into a real ArrayList:

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

public class Main {
    public static void main(String[] args) {
        Integer[] nums = {1, 2, 3};
        List list = new ArrayList<>(Arrays.asList(nums));
        list.add(4);
        System.out.println(list);
    }
}

Output:

[1, 2, 3, 4]

A related pitfall: calling Arrays.binarySearch on an unsorted array does not throw an error—it just returns an unreliable index, because the algorithm assumes sorted input without checking. Always Arrays.sort first.

Best Practices

  • Always use Arrays.toString or Arrays.deepToString to display array contents; never print the array reference directly.
  • Sort with Arrays.sort before calling Arrays.binarySearch—the search silently gives wrong answers on unsorted input.
  • Use Arrays.equals for 1D arrays and Arrays.deepEquals for multi-dimensional or nested arrays; never rely on ==, which only compares references.
  • Prefer Arrays.copyOf/copyOfRange over manual copy loops—they are implemented with fast native memory copies.
  • Remember Arrays.asList is backed by the original array and is fixed-size; wrap it in new ArrayList<>(...) if you need to add or remove elements.
  • For object arrays, pass a Comparator to Arrays.sort when you need a non-natural order (descending, by field, etc.).

Practice Exercises

  • Exercise 1: Given int[] temps = {72, 68, 90, 61, 85};, write a program that prints the array, sorts it, then uses Arrays.binarySearch to find the index of 85 after sorting.
  • Exercise 2: Create a String[] of five fruit names in random order. Sort them alphabetically and print the result, then sort them by length using a custom Comparator and print that result too.
  • Exercise 3: Create two 2D int arrays with identical contents but built separately (not the same reference). Use Arrays.equals and Arrays.deepEquals on them and print both results, explaining in a comment why they differ.

Summary

  • java.util.Arrays is a final utility class of static methods for working with arrays—it can never be instantiated.
  • sort and fill mutate the array in place; copyOf and copyOfRange return brand-new arrays.
  • binarySearch only works correctly on a sorted array.
  • Use toString/deepToString to print arrays, and equals/deepEquals to compare them—never print or compare an array directly.
  • asList gives a fixed-size, array-backed List view; wrap it in an ArrayList for a resizable list.