Home > Software design >  Why many people say that flatmap in reactor is one-to-many?
Why many people say that flatmap in reactor is one-to-many?

Time:01-13

I've read that enter image description here

And quote:

The map is for synchronous, non-blocking, one-to-one transformations while the flatMap is for asynchronous (non-blocking) One-to-Many transformations.

Based on that picture and quote I understand that flatMap allows the creation of more (or fewer) elements than it was in the initial Flux. But all examples I was able to find contains the same amount of element in the initial sequence after flatMap like here:

Flux<Player> players = Flux.just("Zahid Khan", "Arif Khan", "Obaid Sheikh")
    .flatMap(fullname -> Mono
        .just(fullname)
        .map(p -> {
            String[] split = p.split("\\s");
             return new Player(split[0], split[1]);
        })
        .subscribeOn(Scheduler.parallel()));

3 strings as input and 3 players as output:

List<Player> playerList = Arrays.asList(
    new Player("Zahid", "Khan"),
    new Player("Arif", "Khan"), 
    new Player("Obaid", "Sheikh"));

My question is:

Is there a way to modify my example to achieve 3 strings as input and 6 (for example) players as output to prove that flatmap could be one-to-many?

CodePudding user response:

"Many" does not necessarily lead to "more". The term "one-to-many" is often shortened to 1:N where N stands for anything - it can be zero, one, or even ten.

In your example, you flatMap each element into a single one (Mono.just(..) Mono#map(..)). There can be various numbers of items depending on implementation.

FlatMap as one to zero

The simplest example where flatMap results in no element:

Flux.just("Zahid Khan", "Arif Khan", "Obaid Sheikh")
    .flatMap(fullName -> Mono.empty())
    .subscribe(System.out::println);

FlatMap as one to one

This is exactly your example. I would simplify it a bit:

Flux.just("Zahid Khan", "Arif Khan", "Obaid Sheikh")
    .flatMap(fullName -> {
        String[] split = fullName.split("\\s");
        return Mono.just(new Player(split[0], split[1]));
    })
    .subscribe(System.out::println);
Player(name=Zahid, surname=Khan)
Player(name=Arif, surname=Khan)
Player(name=Obaid, surname=Sheikh)

FlatMap as one to many (more than one)

In this case, we yield 2 players from each input (father and junior):

Flux.just("Zahid Khan", "Arif Khan", "Obaid Sheikh")
    .flatMap(fullName -> {
        String[] split = fullName.split("\\s");
        return Flux.just(
            new Player(split[0], split[1]),
            new Player(split[0], split[1]   " Jr."));
        })
    .subscribe(System.out::println);
Player(name=Zahid, surname=Khan)
Player(name=Zahid, surname=Khan Jr.)
Player(name=Arif, surname=Khan)
Player(name=Arif, surname=Khan Jr.)
Player(name=Obaid, surname=Sheikh)
Player(name=Obaid, surname=Sheikh Jr.)

CodePudding user response:

I would like to point one thing:

Difference between .map() and .flatMap() is quite simple:

.map() is meant to map given object to another object (or to the same object, if you want just to change something within that object). This operation is fully synchronous.

.flatMap() is meant to create another Publisher (can either be Mono or Flux) with given object

Emissions from Publisher inside .flatMap() will be "merged" with "main" sequence.

This operation is asynchronous

EDITED: Examples of .flatMap() that returns:

Mono ("one-to-one"):

Flux.just("Hello")
        .flatMap(word -> Mono.just(word   " world!"))  // return Mono that produces another value
        .subscribe(System.out::println);

Which will print the following output:

Hello world!

Flux: ("one-to-many"):

Flux.just("Hello", " world!")
        .flatMap(word -> Flux.fromArray(word.split("(?!^)")))  // return Flux that produces the letters of the given word
        .subscribe(System.out::println);

Which will print the following output:

H
e
l
l
o
 
w
o
r
l
d
!
  • Related