Flux.concat与Flux.concatWith的差异及适用场景咨询
Flux.concat() and concatWith() in Project Reactor? Question:
I'm a beginner in reactive streams, learning to merge two publishers (specifically Flux) using concat/concatWith methods. I found that everything I can do with concat can also be done with concatWith. Here's my sample code:
Mono<String> mono1 = Mono.just(" karan "); Mono<String> mono2 = Mono.just(" | verma "); Mono<String> mono3 = Mono.just(" | kv "); Flux<String> flux1 = Flux.just(" {1} ","{2} ","{3} ","{4} " ); Flux<String> flux2 = Flux.just(" |A|"," |B| "," |C| "); // Flux emits an element every 1000ms Flux<String> intervalFlux1 = Flux.interval(Duration.ofMillis(1000)) .zipWith(flux1, (i, string) -> string); // Flux emits an element every 1000ms Flux<String> intervalFlux2 = Flux .interval(Duration.ofMillis(1000)) .zipWith(flux2, (i, string) -> string); System.out.println("**************Flux Concat***************"); Flux.concat(mono1, mono2, mono3).subscribe(System.out::print); System.out.println(); Flux.concat(flux2, flux1).subscribe(System.out::print); System.out.println(); Flux.concat(intervalFlux2, flux1).subscribe(System.out::print); Thread.sleep(5000); System.out.println(); Flux.concat(intervalFlux2, intervalFlux1).subscribe(System.out::print); Thread.sleep(10000); System.out.println("----------------------------------------"); System.out.println("**************Flux Concat with***************"); mono1.concatWith(mono2).concatWith(mono3).subscribe(System.out::print); System.out.println(); flux1.concatWith(flux2).subscribe(System.out::print); System.out.println(); intervalFlux1.concatWith(flux2).subscribe(System.out::print); Thread.sleep(5000); System.out.println(); intervalFlux1.concatWith(intervalFlux2).subscribe(System.out::print); Thread.sleep(10000); System.out.println(); System.out.println("----------------------------------------");
The output for both methods is as follows:
**************Flux Concat*************** karan | verma | kv |A| |B| |C| {1} {2} {3} {4} |A| |B| |C| {1} {2} {3} {4} |A| |B| |C| {1} {2} {3} {4} ---------------------------------------- **************Flux Concat with*************** karan | verma | kv {1} {2} {3} {4} |A| |B| |C| {1} {2} {3} {4} |A| |B| |C| {1} {2} {3} {4} |A| |B| |C| ----------------------------------------
And their time complexity is similar too. What are the differences between these two methods? Are there specific scenarios where I should prefer concat or concatWith?
Answer:
Great question! It’s totally normal to see these two as interchangeable at first—they both implement the core concatenation behavior: subscribing to publishers one after another, only moving to the next once the current one completes (no interleaving of elements, unlike merge). But there are practical differences that make each better suited for specific situations:
1. Parameter Flexibility & Call Style
Flux.concat()is a static method designed to handle multiple publishers in one go. You can pass individual publishers, an array, or anIterable(like aList<Flux>). For example, your code merging threeMonos is way cleaner withFlux.concat(mono1, mono2, mono3)than chaining threeconcatWith()calls. It’s the go-to choice when you have a fixed set of sources to combine upfront.concatWith()is an instance method that lets you chain merges one at a time. It’s ideal for fluent, step-by-step Flux construction—say you’ve already got a Flux with some operators (likemaporfilter) applied, and you want to append another publisher without breaking the chain. For example:flux1.map(String::trim) .filter(s -> !s.isEmpty()) .concatWith(flux2) // Smoothly continues the chain .subscribe(System.out::print);
2. Readability for Different Numbers of Sources
- If you’re merging 2-3 sources, either works fine. But once you’re combining 4+ sources,
Flux.concat()becomes much more readable. Compare:Flux.concat(fluxA, fluxB, fluxC, fluxD, fluxE)fluxA.concatWith(fluxB).concatWith(fluxC).concatWith(fluxD).concatWith(fluxE)
The first line is far easier to scan and maintain.
3. Advanced Control with Overloads
Flux.concat()has additional overloads that let you control backpressure via a prefetch count (e.g.,concat(int prefetch, Publisher<?>... sources)). This is useful when working with large numbers of sources or when you need to tune how many elements are requested from each publisher upfront.concatWith()doesn’t offer this level of control—it uses the default prefetch settings.
4. Handling Collections of Sources
- If your sources are stored in a collection (like a
List<Flux<String>>),Flux.concat()can take that collection directly:
WithList<Flux<String>> fluxList = Arrays.asList(flux1, flux2, flux3); Flux.concat(fluxList).subscribe(...);concatWith(), you’d have to iterate and chain them manually, which is cumbersome.
When to Choose Which?
- Pick
Flux.concat()when:- You need to merge 3+ publishers at once
- Your sources are in a collection/array
- You want to tune prefetch behavior for backpressure
- Pick
concatWith()when:- You’re building a Flux in a fluent chain and want to append a single publisher
- You’re merging only 2 sources and prefer the chained style
At the end of the day, they’re two sides of the same coin—just optimized for different coding patterns!
内容的提问来源于Stack Exchange,提问作者KayV

