Higher-order stream flattening handles the most common concurrency shape in real applications: a stream whose values are themselves streams. A search box emits keystrokes; each keystroke should trigger an HTTP request; each HTTP request is a stream of one response. The question is not whether to flatten—you must—but how, because each strategy makes a distinct concurrency contract. `mergeMap` (also called `flatMap`) subscribes to every inner Observable concurrently and emits results as they arrive, in no guaranteed order. This is maximum throughput, but order is lost. When an inner Observable errors, the outer stream aborts—a behavior defined at reactivex.io. Uber's data pipelines use merge semantics for independent fan-out work where ordering is irrelevant. `switchMap` cancels the previous inner Observable the moment a new outer emission arrives. This is the canonical choice for live search: when the user types another character, the previous HTTP request is abandoned. Spring WebFlux uses switchMap internally for cancellable reactive queries. The behavior is not just a performance optimization—it is a correctness guarantee that stale responses cannot arrive after fresher ones. `concatMap` queues inner Observables and subscribes to them one at a time in strict emission order. This is essential for ordered sequential operations—payment processing steps, sequential file writes, or any workflow where result N depends on completing step N-1. Throughput is limited to the speed of the slowest inner stream. `exhaustMap` subscribes to the first inner Observable and ignores all outer emissions until it completes. The submit-button use case: if a form submission is in flight, subsequent clicks do nothing until the request finishes. This prevents duplicate submissions without additional boolean guards. Kotlin Flow's `flatMapMerge`, `flatMapConcat`, and `flatMapLatest` (the equivalent of switchMap) map directly to these four strategies. `flatMapLatest` cancels and restarts on each new emission, matching `collectLatest`'s semantics for the case where only the latest value matters. Choosing wrongly here produces either silent data loss (switchMap on ordered operations), unbounded concurrency (mergeMap on a stream that emits faster than inner Observables complete), or a stuck pipeline (concatMap behind a slow inner stream). The decision is architectural, not stylistic.
Comments on "Higher-Order Stream Flattening"
Create a free account or sign in to join the discussion.
Sign in to join the conversation