You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flux.concat与Flux.concatWith的差异及适用场景咨询

Difference between 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 an Iterable (like a List<Flux>). For example, your code merging three Monos is way cleaner with Flux.concat(mono1, mono2, mono3) than chaining three concatWith() 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 (like map or filter) 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:
    List<Flux<String>> fluxList = Arrays.asList(flux1, flux2, flux3);
    Flux.concat(fluxList).subscribe(...);
    
    With 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:57:24