'How can I reverse a single String in Java 8 using Lambda and Streams?

I have one string say "Aniruddh" and I want to reverse it using lambdas and streams in Java 8. How can I do it?



Solution 1:[1]

Given a string like

String str = "Aniruddh";

the canonical solution is

String reversed = new StringBuilder(str).reverse().toString();

If, perhaps for educational purposes, you want to solve this by streaming over the string’s characters, you can do it like

String reversed = str.chars()
    .mapToObj(c -> (char)c)
    .reduce("", (s,c) -> c+s, (s1,s2) -> s2+s1);

This is not only much more complicated, it also has lots of performance drawbacks.

The following solution eliminates boxing related overhead

String reversed = str.chars()
    .collect(StringBuilder::new, (b,c) -> b.insert(0,(char)c), (b1,b2) -> b1.insert(0, b2))
    .toString();

but is still less efficient as inserting into the beginning of an array based buffer implies copying all previously collected data.

So the bottom line is, for real applications, stay with the canonical solution shown at the beginning.

Solution 2:[2]

Try this for reverse a string using lambda and streams

import java.util.stream.Stream;
import java.util.stream.Collectors;

    public class Test  {


        public static void main(String[] args) {

            System.out.println(reverse("Anirudh"));;
        }
        public static String reverse(String string) {
            return Stream.of(string)
                .map(word->new StringBuilder(word).reverse())
                .collect(Collectors.joining(" "));
        }
    }

Solution 3:[3]

If you really want to do it for learning purposes, why not reverse the char array?

public static String reverse(String test) {
    return IntStream.range(0, test.length())
            .map(i -> test.charAt(test.length() - i - 1))
            .collect(StringBuilder::new, (sb, c) -> sb.append((char) c), StringBuilder::append)
            .toString();
}

Solution 4:[4]

Another approach to reversing your String. You can use an IntStream to pull the correct character out of a char array.

public static void main(String[] args) {
    char[] charArray = "Aniruddh".toCharArray();
    IntStream.range(0, charArray.length)
        .mapToObj(i -> charArray[(charArray.length - 1) - i])
        .forEach(System.out::print);
}

Solution 5:[5]

Function<String, String> reverse = s -> new StringBuilder(s).reverse().toString();

Solution 6:[6]

Here is another way, doesn't seem super efficient but will explain why:

String s = "blast";
IntStream.range(0, s.length()).           // create index [0 .. s.length - 1] 
   boxed().                               // the next step requires them boxed
   sorted(Collections.reverseOrder()).    // indices in reverse order
   map(i -> String.valueOf(s.charAt(i))). // grab each index's character 
   collect(Collectors.joining());         // join each single-character String into the final String

It would be better if there was a way to append all the Characters without converting each to String and then joining them. That's why I said it doesn't seem super efficient.

Solution 7:[7]

The easiest way to achieve what you're asking using streams is probably this:

String result = Stream.of("Aniruddh").map(__ -> "hddurinA").findFirst().get();

Solution 8:[8]

Another alternative way would be to split the string into an array of string and use reduce() on it.

Stream.of("Aniruddh".split("")).reduce("", (reversed, character) -> character + reversed);

Solution 9:[9]

Given a String of length S, reverse the whole string without reversing the individual words in it. Words are separated by dots.

String str="abcd.efg.qwerty";

String reversed = Arrays.asList(str.split("\\.")).stream().map(m -> new 
StringBuilder(m).reverse().toString()).collect(Collectors.joining("."));

System.out.println(reversed);

Solution 10:[10]

String str = "Noorus Khan";
       int len = str.length();
        IntStream.range(0, len)
                .map(i -> len - 1 - i)
                .mapToObj(j->str.charAt(j))
                .forEach(System.out::print);

output :: nahK surooN

Solution 11:[11]

Following is another approach to reverse the input String str using Java 8 streams API.

String abc = Arrays.asList(str).stream()
    .map(s -> new StringBuilder(s).reverse().toString())
    .collect(Collectors.toList()).get(0);

Solution 12:[12]

You can use the below technique to reverse a string using stream.

String str = "Aniruddh";

Stream.iterate(str.length()-1, n-> n >= 0, n-> n-1)
        .map(input::charAt)
        .forEach(System.out::print);

Solution 13:[13]

A custom collector can be handy if you want to achieve it with Stream API (I'm treating this task exclusively as an exercise).

Since none of the contributors of this question mentioned this possibility, here's a brief description of how to do that.

Creating a Custom Collector

You can create a custom collector either inline by using one of the versions of the static method Collector.of() or by creating a class that implements the Collector interface.

enter image description here

  • Supplier Supplier<A> is meant to provide a mutable container which store elements of the stream. It could be a Collection, StringBuilder or any other mutable object.
  • Accumulator BiConsumer<A,T> defines how to add elements into the container provided by the supplier.
  • Combiner BinaryOperator<A> combiner() establishes a rule on how to merge two containers in case of parallel execution.
  • Finisher Function<A,R> is meant to produce the final result by transforming the mutable container.
  • Characteristics allows to provide additional information, for instance Collector.Characteristics.UNORDERED signifies that the collector does not guarantee to preserve initial order of elements when the source of the stream is ordered, which can provide better performance in parallel.

The minimum set of parameters boils down to supplier, accumulator and combiner which resembles the arguments of collect() operation with one difference - combiner argument expected by of() (as well as the return type of the combiner() method) is BinaryOperator<A>.

Implementations

The idea behind the first collector is to use ArrayDeque as a mutable container and add each element from the stream of code points to the front of the deque.

Portions of tasks created in parallel will result into several deques has to be combined in reversed order. Therefore, in the combiner the left deque (containing values from closer to the start of the source string) gets appended to the right deque (containing values from closer to the end of the source string), and the right deque is being returned as a result.

Finisher produces an array int[] of code point and returns a string based on it.

Collector<Integer, Deque<Integer>, String>

String source = "abcdefgh";

String reversed = source.codePoints()
    .boxed()
    .collect(Collector.of(
        ArrayDeque::new,
        Deque::addFirst,
        (Deque<Integer> left, Deque<Integer> right) -> { right.addAll(left); return right; },
        (Deque<Integer> deque) -> new String(
            deque.stream().mapToInt(Integer::intValue).toArray(),
            0,
            deque.size())
    ));

The second collector utilizes char[] as its mutable container which is being populated according to the indices of the source IntStream.

Combiner merges two arrays by peek the largest value for each position of the array.

Finisher utilizes constructor new String(char[]) to generate the resulting string.

Collector<Integer, char[], String>

String reversed = IntStream.range(0, source.length())
    .boxed()
    .collect(Collector.of(
        () -> new char[source.length()],
        (char[] arr, Integer i) -> arr[(source.length() - 1) - i] = source.charAt(i),
        (char[] left, char[] right) -> {
            for (int i = 0; i < left.length; i++) left[i] = (char) Math.max(left[i], right[i]); return left;
        },
        String::new
    ));

Output (for string "abcdefgh")

hgfedcba