Reverse a String
Reversing a string is one of the most classic exercises in Java — and it teaches you a lot about how strings actually work under the hood. Because Java strings are immutable, you can never reverse one in-place; you always build a new string. There are several clean ways to do this, and each reveals something useful about the language.
Why You Can’t Reverse In-Place
In languages like C, you can swap characters directly in memory. Java’s String class forbids this — once created, a String object’s contents never change. Every “reversal” must produce a fresh String (or use a mutable type like StringBuilder).
Tip: Because of immutability, the most efficient solutions use
StringBuilderor achar[]array — both are mutable and avoid creating unnecessary intermediateStringobjects.
Method 1: Using StringBuilder (Recommended)
The simplest and most idiomatic approach. StringBuilder has a built-in reverse() method that does exactly what you need in one call.
public class ReverseString {
public static void main(String[] args) {
String original = "Hello, Java!";
String reversed = new StringBuilder(original).reverse().toString();
System.out.println(reversed);
}
}
Output:
!avaJ ,olleH
This is the recommended approach for production code — it is concise, readable, and efficient.
Method 2: Using a char Array
Converting a String to a char[] lets you swap characters in-place inside the array, then reassemble:
public class ReverseWithCharArray {
public static String reverse(String str) {
char[] chars = str.toCharArray();
int left = 0, right = chars.length - 1;
while (left < right) {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
return new String(chars);
}
public static void main(String[] args) {
System.out.println(reverse("DevCraftly")); // ylftharCveD
}
}
Output:
ylftharCveD
This is a classic two-pointer algorithm — O(n) time and O(n) space (for the char array).
Method 3: Iterating Backwards with a Loop
Loop from the last character to the first, appending each character to a StringBuilder:
public class ReverseWithLoop {
public static String reverse(String str) {
StringBuilder sb = new StringBuilder();
for (int i = str.length() - 1; i >= 0; i--) {
sb.append(str.charAt(i));
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(reverse("abcdef")); // fedcba
}
}
Output:
fedcba
Note: Do NOT use
String +=inside the loop. Each+on aStringcreates a new object, making this O(n²) due to how string concatenation works. Always useStringBuilderinside loops.
Method 4: Recursion
Reversing a string recursively is a great mental exercise. The idea: the reverse of "abc" is the reverse of "bc" + "a".
public class ReverseRecursive {
public static String reverse(String str) {
if (str.isEmpty()) {
return str;
}
return reverse(str.substring(1)) + str.charAt(0);
}
public static void main(String[] args) {
System.out.println(reverse("Java")); // avaJ
}
}
Output:
avaJ
Warning: Recursive reversal creates O(n) stack frames and O(n) intermediate
Stringobjects. It is elegant but impractical for large strings — avoid it in production. See Recursion for a deeper dive.
Method 5: Using Java 8 Streams
If you are comfortable with the Stream API, you can reverse a string by streaming its characters:
import java.util.stream.IntStream;
import java.util.stream.Collectors;
public class ReverseWithStream {
public static String reverse(String str) {
return IntStream.rangeClosed(1, str.length())
.mapToObj(i -> String.valueOf(str.charAt(str.length() - i)))
.collect(Collectors.joining());
}
public static void main(String[] args) {
System.out.println(reverse("streams")); // smaerts
}
}
Output:
smaerts
This is functional and expressive, though slightly slower than the StringBuilder approach due to boxing and collector overhead.
Comparison Table
| Method | Mutable? | Readability | Performance | Best For |
|---|---|---|---|---|
StringBuilder.reverse() | Yes | Excellent | Best | General use |
char[] two-pointer | Yes (array) | Good | Excellent | Interviews, large strings |
Loop + StringBuilder | Yes | Good | Excellent | Explicit control |
| Recursion | No | Educational | Poor (large n) | Learning recursion |
| Streams | No | Functional | Moderate | Stream-style code |
Checking if a String is a Palindrome
A palindrome reads the same forwards and backwards. Reversing is the easiest way to check:
public class PalindromeCheck {
public static boolean isPalindrome(String str) {
String reversed = new StringBuilder(str).reverse().toString();
return str.equalsIgnoreCase(reversed);
}
public static void main(String[] args) {
System.out.println(isPalindrome("racecar")); // true
System.out.println(isPalindrome("Java")); // false
}
}
Output:
true
false
Tip: Use
equalsIgnoreCasefor case-insensitive palindrome checks, orstr.toLowerCase()before reversing.
Under the Hood
How StringBuilder.reverse() Works
StringBuilder.reverse() in the JDK iterates over the internal char[] with a two-pointer swap, similar to Method 2 above — but it also handles surrogate pairs correctly. Unicode characters outside the Basic Multilingual Plane (codepoints > U+FFFF) are represented as two char values (a surrogate pair). A naive character-by-character swap would break them apart; StringBuilder.reverse() keeps each pair together.
// Surrogate pair example: 𝄞 (musical symbol G-clef, U+1D11E)
String music = "AB𝄞CD";
System.out.println(new StringBuilder(music).reverse()); // DC𝄞BA
A manual char[] swap without surrogate handling would corrupt the 𝄞 character.
Memory Allocation
new StringBuilder(original) copies the string’s characters into its internal char[] (or byte[] in Java 9+ compact strings). The reverse() call mutates that array in-place. The final .toString() creates a new String that shares (or copies) those bytes. Overall: 2 allocations, O(n) time.
Compact Strings (Java 9+)
Since Java 9, String uses a byte[] internally with a coder flag — LATIN1 (1 byte/char) for ASCII-only strings, UTF16 (2 bytes/char) otherwise. StringBuilder mirrors this. For an ASCII-only string, the reverse() operates on a tightly packed byte array, which is very cache-friendly and fast.
Related Topics
- Strings — the foundation you need before reversing anything
- String Immutability — why strings cannot be changed and what that means for reversal
- StringBuilder — the mutable workhorse behind the fastest reversal methods
- String Methods — the full toolkit of built-in string operations
- Recursion — deeper look at the recursive approach and its tradeoffs
- Stream API — the functional style used in Method 5 above