How to Reverse an Array in Java: int[] and Object Arrays
Reverse Java arrays with two-pointer loops for int[] and object arrays. Understand clones, backed list views, shallow copies, and primitive-array traps.
Reversing an array means exchanging the first element with the last, the second with the second-to-last, and continuing until the indexes meet. In Java, the best implementation depends on whether you have a primitive array such as int[] or a reference array such as String[]. Their elements work with different types, so the same collection shortcut does not apply to both.
For most code, an in-place two-pointer loop is the clearest solution. It needs no dependency and makes mutation explicit. When the original order is still needed, clone first and reverse the clone. The complete program below uses APIs available in Java 8 and later; the compilation command targets Java 17. A separate note explains Java 21’s list-view API.
Reverse an int[] in place
An int[] stores primitive integer values, not Integer references. Java does not automatically box every element so a collection method can consume the array as a list of integers. A small helper can instead swap symmetrical positions directly.
Save this complete program as ReverseArrayDemo.java:
import java.util.Arrays;
import java.util.Objects;
public class ReverseArrayDemo {
public static void main(String[] args) {
int[] numbers = {3, -1, 4, 1, 5};
reverseInPlace(numbers);
System.out.println(Arrays.toString(numbers));
String[] words = {"first", "second", "third"};
reverseInPlace(words);
System.out.println(Arrays.toString(words));
int[] empty = {};
reverseInPlace(empty);
check(empty.length == 0, "empty array remains empty");
int[] sample = {1, 2, 3, 4};
int[] original = sample.clone();
reverseInPlace(sample);
check(Arrays.equals(sample, new int[]{4, 3, 2, 1}), "primitive reversal");
reverseInPlace(sample);
check(Arrays.equals(sample, original), "two reversals restore order");
int[] source = {1, 2, 3};
int[] copy = reversedCopy(source);
check(copy != source, "copy has distinct identity");
check(Arrays.equals(source, new int[]{1, 2, 3}), "source unchanged");
check(Arrays.equals(copy, new int[]{3, 2, 1}), "copy reversal");
System.out.println("Copy: " + Arrays.toString(copy));
System.out.println("Source: " + Arrays.toString(source));
System.out.println("Checks passed");
}
static void reverseInPlace(int[] values) {
Objects.requireNonNull(values, "values");
for (int left = 0, right = values.length - 1;
left < right; left++, right--) {
int temporary = values[left];
values[left] = values[right];
values[right] = temporary;
}
}
static int[] reversedCopy(int[] source) {
Objects.requireNonNull(source, "source");
int[] copy = source.clone();
reverseInPlace(copy);
return copy;
}
static <T> void reverseInPlace(T[] values) {
Objects.requireNonNull(values, "values");
for (int left = 0, right = values.length - 1;
left < right; left++, right--) {
T temporary = values[left];
values[left] = values[right];
values[right] = temporary;
}
}
private static void check(boolean condition, String message) {
if (!condition) {
throw new AssertionError(message);
}
}
}
With a JDK 17 or later installed, compile and run it:
javac --release 17 ReverseArrayDemo.java
java ReverseArrayDemo
Expected output:
[5, 1, 4, -1, 3]
[third, second, first]
Copy: [3, 2, 1]
Source: [1, 2, 3]
Checks passed
The loop starts right at length - 1. For an empty array, that is -1, but the condition is immediately false, so no invalid access occurs. A one-element array also needs no swaps. The same condition handles odd and even lengths; negative values and duplicates need no special treatment.
The helper returns void because its job is to mutate the supplied array. Every alias referring to that array sees the new order. You cannot assign the call to a result variable or chain an operation onto it: a void method produces no value. Call the helper, then read the array separately.
reversedCopy makes the other policy explicit. It creates a different int[], mutates only the copy, and returns it. The original remains unchanged. Both primitive helpers reject a null array through Objects.requireNonNull; the generic overload does the same. This is an explicit API policy rather than an accidental failure inside the swap loop.
Reverse an object array with the generic overload
The type-parameter version uses the same algorithm. Its temporary variable holds a reference, so swapping changes which object occupies each slot without copying or modifying the object itself. The overloads are legal: generic T cannot represent primitive int, so an int[] argument selects the primitive overload rather than T[]. The array itself is still an object; its elements are primitive values.
For a String[], call reverseInPlace(words) as shown in the complete program. The string contents, including characters and Unicode sequences, remain untouched. Only references move. Punctuation attached to a token stays attached, making array reversal useful for word-order transformations without reversing spelling.
For character-level behavior, see the Java string reversal guide. For the token-order distinction, see reversing words without scrambling their letters. Choosing array positions and choosing character boundaries are different problems.
The null check validates the array reference, not each element. A String[] containing {null, "ready"} is valid for this helper: reversal simply moves the null reference to the other position. If your application forbids null elements, validate that separate constraint.
Copying object arrays is shallow
source.clone() creates another array with the same runtime component type, but does not clone the objects stored in its slots. With immutable strings, that distinction is usually unobtrusive. Mutable elements make it visible.
The following fragment belongs inside main, with the generic helper still defined in the class. Run short snippets independently rather than appending duplicate variable declarations to the same scope:
StringBuilder[] words = {
new StringBuilder("first"), new StringBuilder("second")
};
StringBuilder[] copy = words.clone();
reverseInPlace(copy);
copy[0].append("!");
System.out.println(words[1]); // second!
The original array keeps its own slot order, but words[1] and copy[0] refer to the same builder. Changing the builder through one array is visible through the other. The Java Language Specification’s array-cloning discussion explains the shallow nature of array cloning, including shared subarrays.
If independent mutable elements are necessary, create those elements according to your data model. A general reversal helper cannot infer how to clone an application object’s state, external resources, or relationships. Copying positions is not a promise of deep independence.
Use Arrays.asList for a backed object-array view
Collections.reverse targets a List, not an array. For a reference array, Arrays.asList(array) supplies a fixed-size list backed by the array. Although it cannot grow or shrink, it supports element replacement, which reversal needs.
For this snippet, add import java.util.Collections; alongside the complete program’s imports, and place the statements inside main:
String[] words = {"one", "two", "three"};
Collections.reverse(Arrays.asList(words));
System.out.println(Arrays.toString(words)); // [three, two, one]
This expression changes the original array. It does not create an independent reversed result. Replacing an element through the view writes through to the array, while an array-slot assignment is visible through the view. Oracle documents this backing relationship in Arrays.asList and the mutating operation in Collections.reverse.
Why the same shortcut fails for int[]
Add import java.util.List; as well for this separate example:
int[] numbers = {1, 2, 3};
List<int[]> wrapped = Arrays.asList(numbers);
System.out.println(wrapped.size()); // 1
Collections.reverse(wrapped);
System.out.println(Arrays.toString(numbers)); // [1, 2, 3]
The resulting list contains one element: the entire primitive array. It is a List<int[]>, not a list of boxed integers. Reversing a one-element list cannot reverse values inside its element. Java does not automatically convert int[] to Integer[] here.
You can explicitly construct boxed data when a collection API is genuinely required, but that introduces conversion and boxing considerations. For reversing a primitive array, the direct loop avoids that detour. A compiler error when passing an array directly to Collections.reverse is a type mismatch to resolve, not a reason to cast the array into a list.
Know when a list-based method is unsuitable
Collections.reverse returns void and mutates the list. It can throw UnsupportedOperationException when element replacement is unsupported and swaps are needed. An unmodifiable list such as List.of(...), available from Java 9, is not an appropriate target for an intentional in-place reversal. Do not confuse the fixed-size, replaceable Arrays.asList view with an unmodifiable list.
If a reference-array source must remain unchanged, clone it first and reverse the clone using either the generic helper or a view of that clone. The view alone does not provide copying semantics. For primitive values, use the tested reversedCopy helper rather than depending on collection conversions.
For ordinary arrays, an in-place swap loop takes O(n) time and O(1) extra space. A copy-based result needs O(n) additional array storage. A list view does not copy the array, but reversing through it still takes linear work. Recursion adds stack use without improving this simple operation; there is no need for an external dependency just to perform these swaps.
Reversal is not sorting or matrix rotation
Reversal changes positions without comparing values. Reversing {3, 1, 2} produces {2, 1, 3}, not descending {3, 2, 1}. If your requirement is numeric ranking or alphabetic order, sorting is a separate operation. Reversing arbitrary input does not establish an ordering relationship that was absent beforehand.
A two-dimensional Java array has an outer array of row references. Calling the generic helper on int[][] grid = {{1, 2}, {3, 4}} swaps rows to {{3, 4}, {1, 2}}. It does not reverse values within each row, flatten the matrix, or rotate an image 180 degrees.
Use Arrays.deepToString to inspect nested contents rather than the ordinary array object representation. Decide whether the requested operation affects row order, each row’s elements, or some coordinate transformation before selecting a helper. A syntactically valid reversal can still be the wrong transformation.
Test boundaries, identity, and null policy
The complete program contains checks that throw AssertionError on failure without requiring Java’s -ea flag. It checks empty input, a primitive reversal, restoration after two reversals, copy identity, and source preservation. The displayed program and a broader edge-case harness were compiled with --release 17 and run successfully on OpenJDK 21.0.12.1.
In your own tests, include single elements, repeated values, negative numbers, and both odd and even lengths. Check aliasing explicitly: if int[] alias = values, mutating values should be visible through alias, while reversing a clone should leave the source untouched.
For reference arrays, test null elements separately from null array arguments. Check mutable-element sharing and the primitive Arrays.asList trap. These tests catch errors that a short happy-path example misses, especially when replacing a helper with a convenient library expression.
If only a range should be reversed, define its bounds rather than accidentally reversing the entire array. For an end-exclusive range [from, to), validate 0 <= from, from <= to, and to <= values.length before the loop. Initialize left to from and right to to - 1. An empty range may start at the array’s length; the loop must then do nothing, not require each starting index to identify an element.
Repeated range operations deserve a centralized helper with consistent checks. For a one-off operation, a small local loop may be clearer. In either case, document whether bounds are inclusive or exclusive and test an empty range at the end of the array.
Java version note and the practical choice
The complete array program uses Java 8-compatible APIs. The shown --release 17 command requires an appropriate JDK compiler, not only a Java runtime. Java 21 introduced List.reversed(), whose result is a reverse-ordered view rather than an array copy. The Java 21 List documentation documents that view; do not place it in a Java 17 baseline example or mistake it for a primitive-array operation.
Choose reverseInPlace(int[]) when mutation is intended and reversedCopy(int[]) when source order matters. Use the generic overload for reference arrays, or Collections.reverse(Arrays.asList(referenceArray)) when a backed view is appropriate. For a quick text transformation rather than application code, try the Text Reverser tool. The reliable solution is the one that matches both the element type and the caller’s expectations about mutation.
Try the Text Reverser tool
Reverse text, words, or letters instantly — free and entirely in your browser.
Open the tool