1 作用不同1.2 映射?展平?map 只执行映射flatMap 既执行映射,也执行展平什么叫只能执行映射?我理解是把一个数据执行一个方法,转换成另外一个数据。举个例子:mapper 函数把输入的字符串转换成大写。map()方法执行这个 mapper 函数。Function<String, String > mapper = String::toUpperCase; Flux<String> inFlux = Flux.just("hello", ".", "com"); Flux<String> outFlux = inFlux.map(mapper); // reactor 测试包提供的测试方法 StepVerifier.create(outFlux) .expectNext("HELLO", ".", "COM") .expectComplete() .verify();什么叫展平?mapper 函数把字符串转成大写,然后分割成一个一个字符。Function<String, Publisher<String>> mapper = s -> Flux.just(s.toUpperCase().split("")); Flux<String> inFlux = Flux.just("hello", ".", "com"); // 这里只能使用 flatMap,因为参数是 Function<T, Publisher<V>> 形式 Flux<String> outFlux = inFlux.flatMap(mapper); List<String> output = new ArrayList<>(); outFlux.subscribe(output::add); // 输出 [H, E, L, L, O, ., C, O, M] System.out.println(output); 请注意,由于来自不同来源的数据项交错,它们在输出中的顺序可能与我们在输入中看到的不同。1.2 同步?异步?map 是同步的,非阻塞的,1-1(1个输入对应1个输出) 对象转换的;flatMap 是异步的,非阻塞的,1-N(1个输入对应任意个输出) 对象转换的;当流被订阅(subscribe)之后,映射器对输入流中的元素执行必要的转换(执行上述 mapper 操作)。这些元素中的每一个都可以转换为多个数据项,然后用于创建新的流。一旦一个由 Publisher 实例表示的新流准备就绪,flatMap 就会急切地订阅。operator 不会等待发布者完成,会继续下一个流的处理,这意味着订阅是非阻塞的。同时也说明 flatMap() 是异步的。由于管道同时处理所有派生流,因此它们的数据项可能随时进入。结果就是原有的顺序丢失。如果项目的顺序很重要,请考虑改用 flatMapSequential 运算符。2 方法签名的区别很明显2.1 方法签名map 参数是 Function<T, U> ,返回是 Flux<U>flatMap 参数是 Function<T, Publisher<V>> 返回是 Flux<V>举例:这里只能使用 flatMap,因为参数是 Function<T, Publisher<V>> 形式Function<String, Publisher<String>> mapper = s -> Flux.just(s.toUpperCase().split(""));Flux<String> inFlux = Flux.just("hello", ".", "com");// 这里只能使用 flatMap,因为参数是 Function<T, Publisher<V>> 形式Flux<String> outFlux = inFlux.flatMap(mapper);这里只能使用 map,因为参数是 Function<String, String >Function<String, String > mapper = String::toUpperCase;Flux<String> inFlux = Flux.just("hello", ".", "com");// 这里只能使用 map,因为参数是 Function<String, String >Flux<String> outFlux = inFlux.map(mapper);此外,看方法签名,可以看出,可以给 map() 传参 Function<T, Publisher<V>>,按照方法签名,它会返回Flux<Publisher<V>>,但它不知道如何处理 Publishers。比如下面的代码:编译不会报错,但是不知道后续怎么处理。Function<String, Publisher<String>> mapper = s -> Flux.just(s.toUpperCase().split(""));Flux<String> inFlux = Flux.just("hello", ".", "com");Flux<Publisher<String>> map = inFlux.map(mapper);下面的例子来源于 stackoverflow:使用 map 方法会产生 Mono<Mono<T>>,而使用 flatMap 会产生 Mono<T>。使用 map() 就是给 map 传参了Function<T, Publisher<V>>,它返回的也是 Mono<Publisher<V>>。// Signature of the HttpClient.get methodMono<JsonObject> get(String url);// The two urls to callString firstUserUrl = "my-api/first-user";String userDetailsUrl = "my-api/users/details/"; // needs the id at the end// Example with mapMono<Mono<JsonObject>> result = HttpClient.get(firstUserUrl). map(user -> HttpClient.get(userDetailsUrl + user.getId()));// This results with a Mono<Mono<...>> because HttpClient.get(...)// returns a Mono// Same example with flatMapMono<JsonObject> bestResult = HttpClient.get(firstUserUrl). flatMap(user -> HttpClient.get(userDetailsUrl + user.getId()));// Now the result has the type we expected2.3 返回map() 返回一个值的流flatMap() 返回一个流值的流Flux<String> stringFlux = Flux.just("hello word!");Function<String, Publisher<String>> mapper = s -> Flux.just(s.toUpperCase().split(""));// 使用 flatMap() 返回的是 FluxFlatMap.Flux<String> flatMapFlux = stringFlux.flatMap(mapper);// 使用 map() 返回的是 FluxMapFuseableFlux<String> mapFlux = stringFlux.map(s -> s);flatMapFlux 类型是 FluxFlatMap;也就是说,使用 flatMap() 返回的是 FluxFlatMap.mapFlux 类型是 FluxMapFuseable。也就是说,使用 map() 返回的是 FluxMapFuseableFluxMapFuseable 是什么?FluxFlatMap 是什么?FluxFlatMap 和 FluxMapFuseable 是什么区别?各位看官可以一起讨论!参考链接:baeldung: Project Reactor: map() vs flatMap()csdn: map VS flatmapgeeksforgeeks: Difference Between map() And flatMap() In Java StreamstackOverFlow: map vs flatMap in reactor
