Search code examples
javaspring-bootspring-webfluxproject-reactorflatmap

Why many people say that flatmap in reactor is one-to-many?


I've read that wonderful answer about the difference between map and flatMap.

And there is a picture that demonstrates flatmap:

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?


Solution

  • "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.)