How to Reverse a String Using Java Streams (With Examples)

Introduction

Reversing a String is a common Java programming exercise. It involves rearranging the characters of a String so that the last character becomes the first and the first character becomes the last.

For example, reversing the String "Java" produces "avaJ". Java provides a simple way to perform this operation using StringBuilder.reverse(). However, you can also solve the problem using the Java Stream API.

Java Streams are commonly used to process collections and sequences of data. Although the Stream API does not provide a built-in reverse() method, you can use IntStream to process character positions in reverse order.

In this tutorial, I will demonstrate how to reverse a String using Java Streams. You will learn how to use IntStream.range(), reverse Unicode code points, and compare the Stream-based approach with the traditional StringBuilder solution.

1. Understanding String Reversal in Java

String reversal means arranging the characters of a String in the opposite order.

Consider the following input:

Java

The expected output is:

avaJ

The characters change positions as follows:

Position Original String Reversed String
0 J a
1 a v
2 v a
3 a J

Java Strings are immutable. This means you cannot change the characters of an existing String directly.

Instead, a reversal operation creates a new String containing the characters in reverse order.

2. Reverse a String Using IntStream in Java

The IntStream interface provides methods for processing sequences of integer values.

For String reversal, you can use IntStream.range() to generate character indexes. The program then reads those indexes in reverse order and joins the characters into a new String.

This approach is easy to understand if you are already familiar with arrays, indexes, and the Java Stream API.

Java Program Using IntStream.range()

import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class ReverseStringUsingStreams {

    public static void main(String[] args) {

        String input = "Java Streams";

        // Read characters from the last index to the first.
        String reversed = IntStream.range(0, input.length())
                .mapToObj(index ->
                        String.valueOf(
                                input.charAt(input.length() - 1 - index)
                        )
                )
                .collect(Collectors.joining());

        System.out.println("Original String: " + input);
        System.out.println("Reversed String: " + reversed);
    }
}

Output

Original String: Java Streams
Reversed String: smaertS avaJ

How Does the Program Work?

Let's examine the important parts of the program.

Step 1: Generate Character Indexes

IntStream.range(0, input.length())

The IntStream.range() method generates a sequence of integers.

Its first argument is inclusive, while its second argument is exclusive.

For the String "Java", the generated indexes are:

0, 1, 2, 3

These indexes are used to calculate positions starting from the end of the String.

Step 2: Read Characters in Reverse Order

.mapToObj(index ->
        String.valueOf(
                input.charAt(input.length() - 1 - index)
        )
)

The mapToObj() method converts each integer index into a String containing the corresponding character.

The important expression is:

input.length() - 1 - index

This calculates the character position from the end of the String.

For a String containing four characters, the positions are calculated as follows:

Stream Index Calculated Position Character
03a
12v
21a
30J

Step 3: Join the Reversed Characters

.collect(Collectors.joining());

The Collectors.joining() method combines the individual Strings into one String without adding separators.

For the input "Java", the characters "a", "v", "a", and "J" are joined to produce "avaJ".

When should you use this approach?

This approach is useful for learning how to use IntStream, mapToObj(), and Collectors.joining().

However, charAt() works with UTF-16 code units. Reversing individual code units can break characters represented by surrogate pairs, including many emojis. For Unicode-aware reversal, use the next approach.

3. Reverse a Unicode String Using Java Streams

Java Strings can contain Unicode characters such as emojis, symbols, and characters from different writing systems.

Some Unicode characters require two UTF-16 code units. Reversing these code units individually can produce invalid character sequences.

Java provides the codePoints() method to process complete Unicode code points.

In this example, I will convert the String into an array of Unicode code points and use IntStream to process them in reverse order.

Java Program Using String.codePoints()

import java.util.stream.IntStream;

public class ReverseUnicodeStringUsingStreams {

    public static void main(String[] args) {

        String input = "Java 😀 Streams";

        // Convert the String into Unicode code points.
        int[] codePoints = input.codePoints().toArray();

        // Build a new String by reversing the code point order.
        String reversed = IntStream.range(0, codePoints.length)
                .map(index ->
                        codePoints[codePoints.length - 1 - index]
                )
                .collect(
                        StringBuilder::new,
                        StringBuilder::appendCodePoint,
                        StringBuilder::append
                )
                .toString();

        System.out.println("Original String: " + input);
        System.out.println("Reversed String: " + reversed);
    }
}

Output

Original String: Java 😀 Streams
Reversed String: smaertS 😀 avaJ

How Does This Program Work?

Step 1: Convert the String into Unicode Code Points

int[] codePoints = input.codePoints().toArray();

The codePoints() method returns an IntStream of Unicode code points.

The toArray() method stores these values in an integer array.

This allows the program to reverse the order of Unicode code points without splitting valid surrogate pairs.

Step 2: Process Code Points in Reverse Order

IntStream.range(0, codePoints.length)
        .map(index ->
                codePoints[codePoints.length - 1 - index]
        )

The range() method generates indexes from zero to the array length, excluding the upper bound.

The map() operation reads values from the end of the array toward the beginning.

Step 3: Build the Reversed String

.collect(
        StringBuilder::new,
        StringBuilder::appendCodePoint,
        StringBuilder::append
)
.toString();

The three arguments to collect() perform different tasks:

  • StringBuilder::new creates a new StringBuilder.
  • StringBuilder::appendCodePoint appends each Unicode code point.
  • StringBuilder::append combines intermediate StringBuilder results when required.

Finally, toString() converts the StringBuilder into the reversed String.

Important: This approach reverses Unicode code points correctly, but it does not preserve every user-perceived character. Some emojis and accented characters consist of multiple code points. Reversing such sequences can change their visual meaning or appearance.

If your application needs to reverse complete grapheme clusters, use a Unicode text-segmentation solution designed for that purpose.

4. Reverse a String Using StringBuilder

Although this tutorial focuses on Streams, it is useful to understand the traditional Java approach.

The StringBuilder class provides a built-in reverse() method. This is usually the simplest way to reverse a String in Java.

Java Program Using StringBuilder.reverse()

public class ReverseStringUsingStringBuilder {

    public static void main(String[] args) {

        String input = "Java Streams";

        // Reverse the String using StringBuilder.
        String reversed = new StringBuilder(input)
                .reverse()
                .toString();

        System.out.println("Original String: " + input);
        System.out.println("Reversed String: " + reversed);
    }
}

Output

Original String: Java Streams
Reversed String: smaertS avaJ

Explanation

The statement new StringBuilder(input) creates a mutable character sequence containing the original String.

The reverse() method reverses the sequence. The toString() method then creates a String containing the result.

StringBuilder.reverse() also preserves valid UTF-16 surrogate pairs during reversal. However, like code-point reversal, it does not guarantee that multi-code-point grapheme clusters remain intact.

When should you use StringBuilder?

For everyday String reversal, prefer StringBuilder.reverse(). It is concise, readable, and avoids the additional Stream processing required by the other examples.

Use Streams when the objective is to learn Stream operations or integrate reversal into a larger data-processing task.

5. How to Run the Java Programs

You can run these examples using IntelliJ IDEA, Eclipse, VS Code, or the command line.

All examples use standard Java APIs and work with Java 17 or later. No Maven or Gradle dependencies are required.

Step 1: Create a Java File

Create a file named ReverseStringUsingStreams.java.

Copy the complete code from the first Stream example into this file.

Step 2: Compile the Program

Open a terminal in the directory containing the file and run:

javac ReverseStringUsingStreams.java

Step 3: Run the Program

java ReverseStringUsingStreams

The program displays the original and reversed Strings.

To run another example, save its code in a separate Java file with a filename matching the public class name.

6. Comparing Different String Reversal Approaches

The following table compares the approaches covered in this tutorial.

Approach Time Complexity Extra Space Best Use Case
IntStream with charAt() O(n) O(n) Learning Stream operations with basic text
Stream with codePoints() O(n) O(n) Reversing Unicode code points
StringBuilder.reverse() O(n) O(n) General-purpose String reversal

Here, n represents the length of the input String.

All three approaches process the input in linear time and require space for the reversed result.

The Stream-based methods involve additional processing and may allocate more temporary objects.

For most applications, the StringBuilder solution is preferable because it is simpler and avoids unnecessary intermediate processing.

7. Common Mistakes When Reversing a String Using Streams

1. Looking for a Built-In Stream.reverse() Method

Java Streams do not provide a built-in reverse() method.

Instead, you can generate indexes using IntStream.range() and access the elements in reverse order.

2. Reversing UTF-16 Code Units Without Considering Unicode

Using charAt() or chars() may split supplementary Unicode characters when their code units are reversed individually.

For code-point-aware reversal, use String.codePoints().

3. Using Parallel Streams Unnecessarily

String reversal is an ordered operation. The output must follow a specific sequence.

The examples in this tutorial use sequential streams to keep the behavior straightforward.

Parallel processing usually offers no practical advantage for small String reversal tasks.

4. Forgetting About Empty Strings

An empty String should produce another empty String.

The Stream examples handle this naturally because no characters are processed.

5. Not Handling Null Input

Calling methods on a null reference causes a NullPointerException.

If you create a reusable String reversal method, define how it should handle null input.

For example, you can reject null input with a clear exception:

if (input == null) {
    throw new IllegalArgumentException("Input cannot be null");
}

6. Assuming String Reversal Always Preserves Words

Reversing a String character by character changes the order of all characters, including spaces.

For example, reversing "Hello Java" produces "avaJ olleH".

If your goal is to reverse the order of words while keeping each word unchanged, you need a different algorithm.

8. Frequently Asked Questions

Can Java Streams reverse a String?

Yes. Although Streams do not have a built-in reverse() method, you can use IntStream.range() to generate indexes and read characters in reverse order.

How do you reverse a String using IntStream in Java?

Generate a range of indexes from zero to the String length. Use length - 1 - index to access characters from the end, then combine the results using Collectors.joining().

Can I reverse a String using Java Streams without StringBuilder?

Yes. The first example uses IntStream and Collectors.joining() without explicitly creating a StringBuilder. The collector handles the process of combining the Strings internally.

Which is better: Java Streams or StringBuilder for reversing a String?

For general-purpose String reversal, StringBuilder.reverse() is usually the better choice. It requires less code and avoids additional Stream processing.

The Stream approach is useful for understanding functional-style processing and working with indexed data.

How can I reverse a String containing emojis?

You can use String.codePoints() to process complete Unicode code points and rebuild the String in reverse order.

However, some visible emoji sequences contain multiple code points. Preserving such sequences requires grapheme-cluster-aware processing.

What is the time complexity of reversing a String using Streams?

The approaches shown in this tutorial have O(n) time complexity, where n is the length of the String. They also require O(n) space to store the reversed result and any intermediate data.

Does reversing a String modify the original String?

No. Java Strings are immutable. Reversing a String creates a new String, leaving the original value unchanged.

Conclusion

In this tutorial, you learned how to reverse a String using Java Streams and the IntStream API.

The first approach uses IntStream.range() to generate character indexes and Collectors.joining() to build the reversed String. This is a useful way to practice indexed Stream operations.

You also learned how to reverse Unicode code points using String.codePoints(). This approach avoids splitting valid surrogate pairs when processing supplementary Unicode characters.

For everyday String reversal, StringBuilder.reverse() remains the simplest and most practical solution. The Stream-based approaches are most valuable when you want to learn the Stream API or apply similar techniques to other sequence-processing problems.

As a next step, try writing a Java program that reverses the order of words in a sentence without reversing the characters inside each word. This is another useful String programming exercise that builds on the concepts covered in this tutorial.

Continue Learning with Java Guides

Want to take your programming skills to the next level? Explore my practical Udemy courses on Java, Spring Boot, Microservices, Full-Stack Development, Docker, and Generative AI. You can also follow my structured learning roadmaps to become a professional developer.

By Ramesh Fadatare - Udemy Instructor Partner

Comments