1 different role
1.2 Mapping? Flatten?
- map only performs the mapping
- flatMap performs both mapping and flattening
What is the execution-only mapping?
My understanding is to execute a method on one data and convert it into another data. For example: the mapper function converts the input string to uppercase. The map() method executes the mapper function.
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();
What is flattening?
The mapper function converts the string to uppercase and splits it into characters.
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);
Note that due to the interleaving of data items from different sources, their order in the output may differ from what we see in the input.
1.2 Sync? asynchronous?
- map is synchronous, non-blocking, 1-1 (1 input corresponds to 1 output) object conversion;
- flatMap is asynchronous, non-blocking, 1-N (1 input corresponds to any output) object conversion;
After the stream is subscribed, the mapper performs the necessary transformations on the elements in the input stream (performs the mapper operations described above). Each of these elements can be transformed into multiple data items, which can then be used to create new streams.
Once a new stream represented by the Publisher instance is ready, flatMap subscribes eagerly. The operator does not wait for the publisher to complete and continues processing the next stream, which means the subscription is non-blocking. It also shows that flatMap() is asynchronous.
Since pipelines process all derived streams simultaneously , their data items may come in at any time. The result is that the original order is lost. If the order of items is important, consider using the flatMapSequential operator instead.
2 The difference between method signatures is obvious
2.1 Method Signature
- The map parameter is
Function<T, U>
, the return isFlux<U>
- The flatMap parameter is
Function<T, Publisher<V>>
the return isFlux<V>
Example:
Only flatMap can be used here, because the parameter is of the form 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);
Only map can be used here because the parameter is 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);
In addition, looking at the method signature, it can be seen that you can pass parameters to map() Function<T, Publisher<V>>
, according to the method signature, it will return Flux<Publisher<V>>
, but it does not know how to deal with Publishers. For example, the following code: the compilation will not report an error, but I don't know how to deal with it later.
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);
The following example is from stackoverflow:
Using the map method yields Mono<Mono<T>>
and using flatMap yields Mono<T>
. Using map() is to pass parameters to map Function<T, Publisher<V>>
, and it returns 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 Return
- map() returns a stream of values
- flatMap() returns a stream of stream values
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);
The type of flatMapFlux is FluxFlatMap; that is, using flatMap() returns a FluxFlatMap.
The mapFlux type is FluxMapFuseable. That is, using map() returns a FluxMapFuseable
What is FluxMapFuseable?
What is FluxFlatMap?
What is the difference between FluxFlatMap and FluxMapFuseable?
The judges can discuss together!
Reference link:
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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。