How to Reverse an Array in Java (In-Place and Otherwise)

Reversing an array is deceptively simple to describe but reveals a lot about a developer's grasp of memory efficiency: do you reverse in-place using O(1) extra space, or do you reach for a new array (or a library method) without thinking about the trade-off? This guide covers every practical approach, from the optimal two-pointer technique to recursive and library-based alternatives.


Advertisement

Problem Statement

Given an array like {10, 20, 30, 40, 50}, the goal is to reverse the order of its elements to get:

{50, 40, 30, 20, 10}

Ideally, this should be done without allocating a second array.


Method 1: Two-Pointer In-Place Reversal (Optimal Approach)

public class ReverseArray {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30, 40, 50};

        int start = 0;
        int end = numbers.length - 1;

        while (start < end) {
            int temp = numbers[start];
            numbers[start] = numbers[end];
            numbers[end] = temp;

            start++;
            end--;
        }

        System.out.println(java.util.Arrays.toString(numbers));
    }
}

This is the textbook-optimal solution. It runs in O(n) time while using only O(1) extra space by moving two pointers toward the center of the array.


Method 2: Using an Extra Array

int[] numbers = {10, 20, 30, 40, 50};
int[] reversed = new int[numbers.length];

for (int i = 0; i < numbers.length; i++) {
    reversed[i] = numbers[numbers.length - 1 - i];
}

This approach is easier for beginners to understand but requires O(n) additional space. It is useful when you want to preserve the original array while creating a reversed copy.


Method 3: Recursive Reversal

public static void reverseRecursive(int[] arr, int start, int end) {
    if (start >= end) {
        return;
    }

    int temp = arr[start];
    arr[start] = arr[end];
    arr[end] = temp;

    reverseRecursive(arr, start + 1, end - 1);
}

Call the method as follows:

reverseRecursive(numbers, 0, numbers.length - 1);

This method performs the same in-place swaps as the two-pointer approach but expresses the logic recursively. It is commonly used to demonstrate recursion skills during interviews.


Method 4: Collections.reverse() for Lists

If you're working with a List<Integer> instead of a primitive array:

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

List<Integer> list = new java.util.ArrayList<>(
    Arrays.asList(10, 20, 30, 40, 50)
);

Collections.reverse(list);

Note: Arrays.asList() returns a fixed-size list backed by the original array. Wrapping it in a new ArrayList<>(...) creates a mutable list that can be modified freely.


Step-by-Step Explanation

Two Pointers

The start pointer begins at index 0, while the end pointer begins at the last valid index (length - 1).

The Swap

During each iteration, the values at start and end are exchanged using a temporary variable.

Pointer Movement

After each swap:

  • start moves one position to the right.
  • end moves one position to the left.

The pointers continue moving toward the middle of the array.

Loop Termination

The condition while (start < end) ensures the loop stops once the pointers meet or cross. For arrays with an odd number of elements, the middle element is already in its correct position and doesn't need to move.


Internal Working (Memory View)

For the array:

{10, 20, 30, 40, 50}

The swaps occur as follows:

  • start = 0, end = 4 → {50, 20, 30, 40, 10}
  • start = 1, end = 3 → {50, 40, 30, 20, 10}
  • start = 2, end = 2 → Loop stops

Final result:

{50, 40, 30, 20, 10}

Only ⌊n/2⌋ swaps are required, regardless of the array size. The reversal happens directly inside the original array without creating another array.


Real-Life Analogy

Imagine a line of people standing in a row, and you want to reverse their order without moving anyone off the line. The person at each end swaps places with the person at the opposite end, then the next pair does the same, and the process continues until everyone reaches the correct position. No extra space is needed—only position swaps.


Best Practices

  • Use the two-pointer in-place approach whenever the original array doesn't need to be preserved.
  • Use an extra array only if you need both the original and reversed arrays.
  • Prefer the iterative two-pointer method over recursion in production code because recursion can cause a StackOverflowError on very large arrays.
  • For List objects, use Collections.reverse() instead of writing your own reversal logic.

Common Mistakes

  1. Forgetting to use a temporary variable during the swap, causing values to be overwritten.
  2. Using <= instead of < in the while condition, resulting in an unnecessary self-swap at the midpoint.
  3. Creating a new array when an in-place reversal would be sufficient, wasting memory.
  4. Using recursion for very large arrays, increasing the risk of a StackOverflowError.

Expert Tips

  • A common interview follow-up is: "Can you print an array in reverse order without actually reversing it?" Simply loop from length - 1 down to 0 while printing.
  • The two-pointer technique used here also applies to palindrome checking, partitioning arrays, and many other in-place algorithms.
  • The same swap logic works for object arrays (String[], Integer[], custom objects, etc.); only the data type changes.

Comparison Table

Method Time Complexity Space Complexity Modifies Original?
Two-Pointer In-Place O(n) O(1) Yes
Extra Array O(n) O(n) No (Original Preserved)
Recursive O(n) O(n) (Call Stack) Yes
Collections.reverse() (Lists) O(n) O(1) Yes

Test It With TestNG

public final class ArrayReverser {
    private ArrayReverser() { }

    /** Reverses the array in place using two pointers. */
    public static void reverseInPlace(int[] arr) {
        int start = 0, end = arr.length - 1;
        while (start < end) {
            int temp = arr[start];
            arr[start] = arr[end];
            arr[end] = temp;
            start++;
            end--;
        }
    }

    /** Returns a new reversed array; the input is not changed. */
    public static int[] reversedCopy(int[] arr) {
        int[] result = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            result[i] = arr[arr.length - 1 - i];
        }
        return result;
    }
}
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ArrayReverserTest {

    @DataProvider(name = "arrays")
    public Object[][] arrays() {
        return new Object[][] {
            { new int[]{10, 20, 30, 40, 50}, new int[]{50, 40, 30, 20, 10} },   // odd length
            { new int[]{1, 2, 3, 4},         new int[]{4, 3, 2, 1} },           // even length
            { new int[]{7},                  new int[]{7} },                    // single element
            { new int[]{},                   new int[]{} },                     // empty
            { new int[]{5, 5, 1},            new int[]{1, 5, 5} },              // duplicates
        };
    }

    @Test(dataProvider = "arrays")
    public void reversesInPlace(int[] input, int[] expected) {
        int[] arr = input.clone();
        ArrayReverser.reverseInPlace(arr);
        Assert.assertEquals(arr, expected);
    }

    @Test(dataProvider = "arrays")
    public void reversedCopyLeavesTheInputAlone(int[] input, int[] expected) {
        int[] before = input.clone();
        Assert.assertEquals(ArrayReverser.reversedCopy(input), expected);
        Assert.assertEquals(input, before);
    }

    @Test
    public void collectionsReverseDoesNotWorkOnAnIntArray() {
        int[] numbers = {10, 20, 30};
        List<int[]> wrapped = Arrays.asList(numbers);   // a list with ONE element: the whole array
        Collections.reverse(wrapped);
        Assert.assertEquals(wrapped.size(), 1);
        Assert.assertEquals(numbers, new int[]{10, 20, 30});   // unchanged
    }

    @Test
    public void collectionsReverseOnAnIntegerArrayChangesTheArray() {
        Integer[] numbers = {10, 20, 30};
        Collections.reverse(Arrays.asList(numbers));    // the list is a view over the array
        Assert.assertEquals(Arrays.toString(numbers), "[30, 20, 10]");
    }
}

Result:

PASS collectionsReverseDoesNotWorkOnAnIntArray
PASS collectionsReverseOnAnIntegerArrayChangesTheArray
PASS reversedCopyLeavesTheInputAlone × 5 data sets
PASS reversesInPlace × 5 data sets (odd, even, single, empty, duplicates)
Total: 12, Passed: 12, Failed: 0

We compiled these tests with Java 21 and ran them with a minimal TestNG-compatible runner (the full TestNG library wasn't available in our environment); they use only standard TestNG annotations and Assert methods, so they run unchanged with mvn test in a TestNG project.

Two tests cover a trap that catches experienced developers:

  • Collections.reverse(Arrays.asList(intArray)) does nothing useful. For an int[], Arrays.asList() creates a list containing one element — the whole array — so "reversing" it changes nothing. It compiles without a warning.
  • For an Integer[], the same call does work — and it reverses the original array, because Arrays.asList() returns a view backed by it, not a copy.

The empty and single-element cases confirm the two-pointer loop needs no special handling: with start < end false from the start, it simply doesn't run. Watch the two pointers move toward each other in the Java Code Visualizer.

From Real Projects

Java has been the language of every automation framework I've worked with — Selenium, TestNG, POM classes and Apache POI for Excel data. Interviews for automation roles regularly include basic programs like this one, often followed by a question on OOP concepts. Practice writing it by hand and explaining how you'd test it. On Canolog, the many forms and screens across sales, inventory, finance and service are where keeping page details in POM classes and reusable steps in a business library paid off. Test with an empty array, a single element and an even-length array.

📚 Official documentation: dev.java: Learn Java (Oracle) · Java 21 API documentation

Frequently Asked Questions

What is the most efficient way to reverse an array in Java?

The two-pointer in-place technique is the most efficient because it runs in O(n) time while using only O(1) extra space.

Does reversing an array in-place modify the original array?

Yes. In-place reversal changes the contents of the original array directly.

Can I reverse an array without using any extra memory?

Yes. The two-pointer approach uses only one temporary variable during each swap.

Is recursion a good choice for reversing large arrays?

Generally no. Recursive calls consume stack memory and may lead to a StackOverflowError for very large arrays. The iterative solution is preferred.

How do I print an array in reverse without actually reversing it?

Loop from the last index down to the first while printing each element. This leaves the original array unchanged.

Does the Arrays class provide a built-in reverse method?

No. Java's Arrays class does not provide a built-in reverse method for arrays. For lists, you can use Collections.reverse().

What happens if I use <= instead of < in the while condition?

For arrays with an odd number of elements, the middle element swaps with itself once. This doesn't affect the result but performs an unnecessary operation.

Can the two-pointer technique be used for other problems?

Yes. It is a fundamental algorithmic pattern used in palindrome checking, partitioning arrays, and many other in-place array manipulation problems.