How to Use StringBuilder.reverse() in Java
java stringbuilder reverse: Learn how StringBuilder.reverse() works in Java, its in-place behavior, Unicode edge cases, performance implications, and common pitfalls.
java stringbuilder reverse requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
The StringBuilder class in Java provides a reverse() method that reverses the sequence of characters in place. This method is a direct answer to the common need to reverse a string without creating multiple intermediate objects. Unlike String, which is immutable, StringBuilder is mutable, and reverse() modifies the existing instance rather than returning a new one. The method returns the same StringBuilder reference, allowing for method chaining.
What StringBuilder.reverse() Actually Does
The reverse() method reverses the order of characters in the StringBuilder. For example, if the current content is "abcde", calling reverse() changes it to "edcba". The method returns the same StringBuilder instance, so you can chain other operations after it:
StringBuilder sb = new StringBuilder("hello"); sb.reverse(); System.out.println(sb.toString()); // "olleh"
The reversal happens in place, meaning the original character array is rearranged. No new StringBuilder object is allocated, and the capacity of the underlying buffer remains unchanged. This is a key difference from approaches that create a new String or StringBuilder for each reversal.
How reverse() Handles Unicode and Surrogate Pairs
Java strings are sequences of UTF-16 code units. Most characters fit in a single char, but supplementary characters (such as emojis) are represented as a pair of char values called a surrogate pair. The reverse() method operates on char values, not on full Unicode code points. This means that reversing a string containing surrogate pairs can produce an invalid sequence.
Consider the string "A\uD83D\uDE00B" (which represents A😀B). The surrogate pair \uD83D\uDE00 is two char units. When reverse() is called, the order of these two char values is swapped, resulting in "B\uDE00\uD83DA". The surrogate pair is now in the wrong order, and the resulting string is not a valid Unicode sequence.
String original = "A\uD83D\uDE00B"; // A😀B StringBuilder sb = new StringBuilder(original); sb.reverse(); System.out.println(sb.toString()); // B\uDE00\uD83DA (invalid surrogate order)
If your application handles text that may contain supplementary characters, you need to reverse by code points instead. You can use String.codePoints() to get an array of Unicode code points, reverse that array, and then build a new string:
String original = "A\uD83D\uDE00B"; int[] codePoints = original.codePoints().toArray(); StringBuilder reversed = new StringBuilder(); for (int i = codePoints.length - 1; i >= 0; i--) { reversed.appendCodePoint(codePoints[i]); } System.out.println(reversed.toString()); // B😀A
This approach correctly handles surrogate pairs and other Unicode code points that require two char units.
Performance Considerations of StringBuilder.reverse()
The reverse() method runs in linear time, O(n), where n is the number of characters in the sequence. It swaps the first and last characters, then the second and second-to-last, and so on, until it reaches the middle. Because it operates in place, it does not allocate additional memory for the reversed sequence, aside from a temporary char variable used during each swap.
This makes reverse() more memory-efficient than approaches that create a new String or StringBuilder for each reversal. For example, the common idiom new StringBuilder(str).reverse().toString() creates a new StringBuilder and a new String, but it is still often used because it is concise and the overhead is acceptable for small strings.
If you are reversing very large strings or performing many reversals in a loop, using reverse() on an existing StringBuilder avoids repeated allocations. However, if you only need the reversed result once, the convenience of the one-liner is usually fine.
Common Mistakes When Using reverse()
One frequent mistake is assuming that reverse() returns a new StringBuilder and that the original remains unchanged. Since it mutates the instance, you must be careful if you need to preserve the original order. For example:
StringBuilder sb = new StringBuilder("abc"); StringBuilder reversed = sb.reverse(); // sb is also reversed System.out.println(sb); // "cba" System.out.println(reversed); // "cba"
If you need to keep the original, create a copy before calling reverse():
StringBuilder original = new StringBuilder("abc"); StringBuilder reversed = new StringBuilder(original).reverse();
Another mistake is using StringBuffer instead of StringBuilder. StringBuffer is thread-safe but has synchronized methods, which add overhead. In single-threaded code, StringBuilder is preferred. The reverse() method exists on both classes, but the behavior is identical; the performance difference is due to synchronization.
Alternatives to StringBuilder.reverse()
For simple cases, new StringBuilder(str).reverse().toString() is a concise way to reverse a String. However, if you need to reverse a string that contains surrogate pairs, you should use the code-point-based approach shown earlier. Another alternative is to use Java 8+ streams:
String reversed = str.chars() .mapToObj(c -> (char) c) .reduce("", (s, c) -> c + s, (s1, s2) -> s2 + s1);
This approach is not recommended because it creates many intermediate strings and is inefficient. The StringBuilder approach is almost always better for performance and readability.
If you need to reverse only a portion of the sequence, you can use subSequence() to get a view of the range, but note that subSequence() returns a CharSequence that shares the underlying array. Modifying the original StringBuilder after obtaining a subsequence can lead to unexpected behavior. A safer way is to extract the substring, reverse it, and then replace the original portion using replace():
StringBuilder sb = new StringBuilder("abcdef"); int start = 1; int end = 5; // exclusive String reversedPart = new StringBuilder(sb.substring(start, end)).reverse().toString(); sb.replace(start, end, reversedPart); System.out.println(sb); // "aedcbf"
Thread Safety and StringBuffer vs StringBuilder
StringBuilder is not thread-safe. If multiple threads access the same StringBuilder instance concurrently, and at least one thread calls reverse() or any other mutating method, the results are undefined. For concurrent use, you should either synchronize externally or use StringBuffer, which synchronizes its methods.
StringBuffer.reverse() behaves exactly like StringBuilder.reverse() but with the overhead of acquiring a lock on each call. In single-threaded code, prefer StringBuilder to avoid unnecessary synchronization. In multi-threaded scenarios, consider whether you can avoid sharing a mutable sequence altogether; often it is better to use immutable String values.
When to Use reverse() vs Manual Reversal
For most practical purposes, StringBuilder.reverse() is the simplest and most efficient way to reverse a string in Java. A manual loop that swaps characters is essentially what reverse() does internally, but using the built-in method reduces the chance of off-by-one errors and keeps the code clearer.
Manual reversal may be necessary if you need to reverse only certain characters or apply custom rules, such as ignoring punctuation or reversing word order. In those cases, you would not use reverse() directly but would build a custom algorithm. However, for a plain character reversal, reverse() is the right tool.
One edge case to keep in mind is that reverse() works on the entire sequence. If you need to reverse the order of words in a sentence, you would split the string into words, reverse the list, and join them back. That is a different operation and should not be confused with character reversal.
Compatibility and Version Considerations
The reverse() method has been part of StringBuilder since Java 5, when StringBuilder was introduced as a non-synchronized alternative to StringBuffer. The behavior is stable across all later Java versions. No special imports are needed beyond java.lang.StringBuilder, which is automatically available.
When targeting older Java versions, note that StringBuilder does not exist in Java 1.4 and earlier; you would use StringBuffer instead. For modern Java (8 and later), StringBuilder is the standard choice.
If you are working with a large text buffer and need to reverse it frequently, consider the memory and CPU tradeoffs. The in-place nature of reverse() is efficient, but if the buffer is shared across threads, the lack of thread safety can cause corruption. Always document the concurrency assumptions of your code.