Transform Flux and Mono Using Operators

How to transform Flux and Mono in Java?

We often have to transform the data we receive from one source to send it to another. In the project Reactor, we use the operators to transform Mono and Flux. 

What are operators in Project Reactor?

Operators in Project Reactor are functions that we can call in a chain, just like operators in Java 8 Streams. We use them to convert the input to the desired output.

In this post, we will explore the following operators:

  • map()
  • filter()
  • flatMap()

Working with the Reactive Streams operators

Let’s see some examples where we use the above mentioned operators:

map() operator

Let’s say we have a Flux that contains some names. We want to transform each name into an uppercase. We can do that using the map() operator:

class ReactiveJavaTutorial {

  public static void main(String[] args) {

    Flux.fromArray(new String[]{"Tom", "Melissa", "Steve", "Megan"})
            .map(String::toUpperCase)
            .subscribe(System.out::println);
 
  }
}
Output: TOM MELISSA STEVE MEGAN

Remember: we need to subscribe in order to consume data from the Publisher.

filter() operator

Now, we have a requirement to convert only names whose length is >5. For this, we will use the filter() operator together with map():

class ReactiveJavaTutorial {

  public static void main(String[] args) {

    Flux.fromArray(new String[]{"Tom", "Melissa", "Steven", "Megan"})
            .filter(name -> name.length() > 5)
            .map(String::toUpperCase)
            .subscribe(System.out::println);
 
  }
}
Output: MELISSA STEVEN
 
Note: Reactive Streams are immutable. When we apply some operator on a Flux, we are not changing the original data source. The operator is just returning the new Flux with transformed data.
 
See the following example:
class ReactiveJavaTutorial {

  public static void main(String[] args) {

    Flux<String> flux = Flux.fromArray(new String[]{"Tom", "Melissa", "Steven", "Megan"});

    Flux<String> transformedFlux = flux.map(String::toUpperCase);

    System.out.println("New Flux:");
    transformedFlux.subscribe(name -> System.out.print(name + " "));

    System.out.println();

    System.out.println("Original Flux:");
    flux.subscribe(name -> System.out.print(name + " "));

  }
}
Output: New Flux: TOM MELISSA STEVEN MEGAN Original Flux: Tom Melissa Steven Megan.
 
The original Flux has not changed. Instead, we got a new Flux by calling the map() operator.

flatMap() operator

The flatMap() operator transforms one source element to a Flux of 1 … n elements. We use flatMap() when the transformation returns a Flux or Mono.

Let’s call a function that returns a Mono with the map() operator:

class ReactiveJavaTutorial {

  public static void main(String[] args) {

    Flux.fromArray(new String[]{"Tom", "Melissa", "Steven", "Megan"})
            .map(ReactiveJavaTutorial::putModifiedNameIntoMono)
            .subscribe(System.out::println);

  }

  private static Mono<String> putModifiedNameIntoMono(String name) {
    return Mono.just(name.concat(" modified"));
  }

}
Output: MonoJust MonoJust MonoJust MonoJust
 
You can see that the output of the map() operator was also Mono. Now, let’s replace the map() with a flatMap():
class ReactiveJavaTutorial {

  public static void main(String[] args) {

    Flux.fromArray(new String[]{"Tom", "Melissa", "Steven", "Megan"})
            .flatMap(ReactiveJavaTutorial::putModifiedNameIntoMono)
            .subscribe(System.out::println);

  }

  private static Mono<String> putModifiedNameIntoMono(String name) {
    return Mono.just(name.concat(" modified"));
  }

}
Output: Tom modified Melissa modified Steven modified Megan modified
 
The flatMap() flattens the result and extracts the data from the Mono. So we should use it when we know that we will have one of the Reactive Types as the data source. 
 
That would be all regarding how to transform Flux and Mono in Java. 
 
Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *