共计 3356 个字符,预计需要花费 9 分钟才能阅读完成。
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 method
Mono<JsonObject> 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<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 flatMap
Mono<JsonObject> bestResult = HttpClient.get(firstUserUrl).
flatMap(user -> HttpClient.get(userDetailsUrl + user.getId()));
// Now the result has the type we expected
2.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() 返回的是 FluxMapFuseable
Flux<String> mapFlux = stringFlux.map(s -> s);
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