• Reactor 之 flatMap vs map 详解


    1 作用不同

    1.2 映射?展平?

    • map 只执行映射
    • flatMap 既执行映射,也执行展平

    什么叫只能执行映射?

    我理解是把一个数据执行一个方法,转换成另外一个数据。举个例子:mapper 函数把输入的字符串转换成大写。map()方法执行这个 mapper 函数。

    Function mapper = String::toUpperCase;
    		Flux inFlux = Flux.just("hello", ".", "com");
    		Flux outFlux = inFlux.map(mapper);
    		// reactor 测试包提供的测试方法
    		StepVerifier.create(outFlux)
    				.expectNext("HELLO", ".", "COM")
    				.expectComplete()
    				.verify();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    什么叫展平?

    mapper 函数把字符串转成大写,然后分割成一个一个字符。

    Function> mapper = s -> Flux.just(s.toUpperCase().split(""));
    
    		Flux inFlux = Flux.just("hello", ".", "com");
    		// 这里只能使用 flatMap,因为参数是 Function> 形式
    		Flux outFlux = inFlux.flatMap(mapper);
    
    		List output = new ArrayList<>();
    		outFlux.subscribe(output::add);
    		// 输出 [H, E, L, L, O, ., C, O, M]
        System.out.println(output);    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    请注意,由于来自不同来源的数据项交错,它们在输出中的顺序可能与我们在输入中看到的不同。

    1.2 同步?异步?

    • map 是同步的,非阻塞的,1-1(1个输入对应1个输出) 对象转换的;
    • flatMap 是异步的,非阻塞的,1-N(1个输入对应任意个输出) 对象转换的;

    当流被订阅(subscribe)之后,映射器对输入流中的元素执行必要的转换(执行上述 mapper 操作)。这些元素中的每一个都可以转换为多个数据项,然后用于创建新的流。

    一旦一个由 Publisher 实例表示的新流准备就绪,flatMap 就会急切地订阅。operator 不会等待发布者完成,会继续下一个流的处理,这意味着订阅是非阻塞的。同时也说明 flatMap() 是异步的。

    由于管道同时处理所有派生流,因此它们的数据项可能随时进入。结果就是原有的顺序丢失。如果项目的顺序很重要,请考虑改用 flatMapSequential 运算符。

    2 方法签名的区别很明显

    2.1 方法签名

    • map 参数是 Function ,返回是 Flux
    • flatMap 参数是 Function> 返回是 Flux

    举例:

    这里只能使用 flatMap,因为参数是 Function> 形式

    Function> mapper = s -> Flux.just(s.toUpperCase().split(""));
    
    Flux inFlux = Flux.just("hello", ".", "com");
    // 这里只能使用 flatMap,因为参数是 Function> 形式
    Flux outFlux = inFlux.flatMap(mapper);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里只能使用 map,因为参数是 Function

    Function mapper = String::toUpperCase;
    Flux inFlux = Flux.just("hello", ".", "com");
    // 这里只能使用 map,因为参数是 Function
    Flux outFlux = inFlux.map(mapper);
    
    • 1
    • 2
    • 3
    • 4

    此外,看方法签名,可以看出,可以给 map() 传参 Function>,按照方法签名,它会返回Flux>,但它不知道如何处理 Publishers。比如下面的代码:编译不会报错,但是不知道后续怎么处理。

    Function> mapper = s -> Flux.just(s.toUpperCase().split(""));
    Flux inFlux = Flux.just("hello", ".", "com");
    Flux> map = inFlux.map(mapper);
    
    • 1
    • 2
    • 3

    下面的例子来源于 stackoverflow:

    使用 map 方法会产生 Mono>,而使用 flatMap 会产生 Mono。使用 map() 就是给 map 传参了Function>,它返回的也是 Mono>

    // Signature of the HttpClient.get method
    Mono get(String url);
    
    // The two urls to call
    String firstUserUrl = "my-api/first-user";
    String userDetailsUrl = "my-api/users/details/"; // needs the id at the end
    
    // Example with map
    Mono> result = HttpClient.get(firstUserUrl).
      map(user -> HttpClient.get(userDetailsUrl + user.getId()));
    // This results with a Mono> because HttpClient.get(...)
    // returns a Mono
    
    // Same example with flatMap
    Mono bestResult = HttpClient.get(firstUserUrl).
      flatMap(user -> HttpClient.get(userDetailsUrl + user.getId()));
    // Now the result has the type we expected
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.3 返回

    • map() 返回一个值的流
    • flatMap() 返回一个流值的流
    Flux stringFlux = Flux.just("hello word!");
    Function> mapper = s -> Flux.just(s.toUpperCase().split(""));
    // 使用 flatMap() 返回的是 FluxFlatMap.
    Flux flatMapFlux = stringFlux.flatMap(mapper);
    // 使用 map() 返回的是 FluxMapFuseable
    Flux mapFlux = stringFlux.map(s -> s);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    flatMapFlux 类型是 FluxFlatMap;也就是说,使用 flatMap() 返回的是 FluxFlatMap.

    mapFlux 类型是 FluxMapFuseable。也就是说,使用 map() 返回的是 FluxMapFuseable

    FluxMapFuseable 是什么?

    FluxFlatMap 是什么?

    FluxFlatMap 和 FluxMapFuseable 是什么区别?

    各位看官可以一起讨论!

    参考链接:

    baeldung: Project Reactor: map() vs flatMap()

    csdn: map VS flatmap

    geeksforgeeks: Difference Between map() And flatMap() In Java Stream

    stackOverFlow: map vs flatMap in reactor

  • 相关阅读:
    使用Java合并PDF文档
    【JVM 系列】JVM 调优
    内网渗透-linux权限维持
    java计算机毕业设计宠物云寄养系统源码+系统+lw文档+mysql数据库+部署
    【论文精读】Robust Alignment for Panoramic Stitching Via an Exact Rank Constraint
    SpringCloud 微服务全栈体系(六)
    学习心得08:OpenGL
    webshell流量特征
    英语单词同义词辨析
    22. 括号生成
  • 原文地址:https://blog.csdn.net/Prepared/article/details/126429163