Flow
Flow is Kotlin's reactive stream type built on coroutines: cold producers, a rich operator set, hot StateFlow and SharedFlow for shared state and events, and backpressure through suspension. Any Android or streaming-backend interview goes here after coroutines.
part ofKotlinoverview, primer and where to startread it →on this pageshowhide
explore
- How Kotlin Does Reactive Streams5 questions
- Cold Flows21 questions
- flow{} Builder & emit/collect5 questions
- Cold Semantics & Laziness5 questions
- flowOf / asFlow Builders5 questions
- Context Preservation & flowOn6 questions
- Operators20 questions
- map / filter / transform5 questions
- zip / combine / merge5 questions
- flatMapConcat / flatMapMerge / flatMapLatest5 questions
- Terminal Operators5 questions
- Hot Flows15 questions
- StateFlow & MutableStateFlow5 questions
- SharedFlow & MutableSharedFlow5 questions
- shareIn / stateIn5 questions
- Backpressure15 questions
- buffer & Overflow Strategies5 questions
- conflate5 questions
- collectLatest & mapLatest5 questions
- Channel-Backed Flows15 questions
- Channel vs Flow5 questions
- channelFlow5 questions
- callbackFlow5 questions
- Error & Completion15 questions
- onStart / onCompletion5 questions
- catch & Exception Transparency5 questions
- retry / retryWhen5 questions
questions
106 · 7 sectionsWhat is a Kotlin Flow, and how does it relate to a regular list and to reactive streams like RxJava's Observable?
basics
~10 sA Flow is a stream of values produced over time, one after another. Unlike a list, the values can arrive asynchronously without blocking. It is Kotlin's coroutine-based answer to reactive streams.
What does it mean that Flow is "cold," and what runs the flow's producer block? Show what happens if no one collects.
basics
~10 sCold means the flow does nothing until someone collects it. The producer code only runs when collect is called, and it runs fresh for each collector. No collector, no work.
Explain how a Flow integrates with structured concurrency: in whose context does emission run, and how does cancellation propagate?
basics
~10 sA flow runs inside the coroutine that collects it. So it uses that coroutine's thread and lifecycle: if the collecting coroutine is cancelled, the flow stops too. Producer and consumer share one structured scope.
How does Flow handle backpressure without an explicit request(n) mechanism like Reactive Streams?
basics
~20 sWhen the collector is slow, the producer's emit call simply suspends and waits. No values are dropped or buffered by default — the producer politely pauses until the collector is ready for the next value.
Why did Kotlin model Flow as cold and suspend-based rather than adopting the Reactive Streams Publisher/Subscriber callback model? What trade-offs does that create, including interop?
basics
~20 sBuilding Flow on coroutines lets async stream code read like normal sequential code, with built-in cancellation and backpressure via suspension. The trade-off is that the default Flow lacks multicasting and needs adapters to talk to RxJava/Reactor.
What does flowOf(...) do, and how does it differ from a list of values?
basics
~10 sflowOf takes a fixed set of values and wraps them in a Flow, emitting each one in order when you collect it. A list just holds values; a Flow streams them on demand.
What is the flow { } builder in Kotlin, and what does it mean that the flow it creates is 'cold'?
basics
~10 sflow { } makes a stream of values. Inside the block you call emit(value) to send each item. Nothing runs until someone collects it. A cold flow re-runs its code fresh for every collector.
What does it mean that a Kotlin Flow is "cold", and what does that imply about when its code runs?
basics
~10 sA cold Flow does nothing on its own. The code inside it runs only when you collect it. Until someone collects, no values are produced and no work happens.
In Kotlin Flow, what does 'context preservation' mean, and in which coroutine context does emit run by default?
basics
~10 sIt means the code that produces values runs in the same place that collects them. By default, emit runs in the collector's coroutine, so the flow uses whatever context the collector started in.
How does asFlow() work for Iterable and Sequence, and when would you use it over flowOf?
basics
~20 sasFlow() is an extension that turns something you already have — a list, sequence, or range — into a Flow that emits each element. Use it when the values live in a collection; use flowOf for literal values you type out.
What is the difference between zip and combine when joining two Flows in Kotlin?
basics
~10 szip waits for one new item from each flow and pairs them in lockstep. combine fires whenever either flow emits, using the newest value from the other flow.
What problem do flatMapConcat, flatMapMerge, and flatMapLatest solve in Kotlin Flow, and how do they differ at a high level?
basics
~20 sEach emitted value can itself produce a flow. These operators flatten those inner flows into one stream. Concat runs them one after another, Merge runs them at the same time, Latest cancels the old inner flow when a new value comes.
What is a terminal operator on a Kotlin Flow, and why must you call one for any code to run? Give two examples.
basics
~10 sA terminal operator is the function that actually starts a Flow running and consumes its values. Without one, nothing happens because Flows are lazy. Examples: collect and toList.
What do the map and filter intermediate operators do on a Kotlin Flow, and why are they 'cold' and 'lazy'?
basics
~10 smap turns each emitted value into a new value; filter keeps only values matching a condition. They do nothing until a terminal operator (like collect) runs the flow, and each collection re-runs the work.
Explain the ordering and concurrency guarantees of flatMapConcat versus flatMapMerge, including the concurrency argument and its default.
basics
~20 sConcat processes inner flows one at a time, so output keeps the input order. Merge processes several at once, so faster inner flows can finish first and outputs interleave. Merge lets you cap how many run together; the default is 16.
What is StateFlow in Kotlin coroutines, and how does it differ from a plain (cold) Flow?
basics
~10 sStateFlow is a flow that always holds one current value you can read at any time through .value. A plain Flow holds nothing on its own and only produces values when someone collects it.
What does the buffer() operator do to a Kotlin Flow, and why would you add it to a pipeline?
basics
~20 sbuffer() lets the part producing values and the part collecting them run at the same time instead of taking turns. Producers can race ahead into a small queue, so a slow collector no longer slows the producer.
What does Flow's collectLatest do, and how is it different from a plain collect?
basics
~20 scollectLatest runs your handling code for each value, but if a new value arrives before the previous one finishes, it stops the previous work and starts on the new value. Plain collect always finishes every value first.
What does the conflate() operator do to a Kotlin Flow, and when would you reach for it?
basics
~20 sconflate() lets a fast producer skip ahead: if the collector is busy, in-between values are dropped and it only gets the newest one. Good when you only care about the latest value, like a live counter.
Explain the three BufferOverflow strategies for buffer() and what each does when the buffer is full.
basics
~20 sWhen the buffer fills up: SUSPEND pauses the producer until there is room (nothing lost); DROP_OLDEST throws away the oldest queued item to make space for the new one; DROP_LATEST throws away the new item and keeps what is already queued.
Why might collectLatest fail to cancel an in-flight block, and how do you make CPU-bound work in the block actually cancellable?
basics
~20 sCancellation only happens when the running code reaches a pause point. If your block does heavy non-stop computation, there's no pause point, so the old block keeps running. Add checks like ensureActive() or yield() so it can stop.
What is callbackFlow and when would you reach for it instead of the plain flow { } builder?
basics
~10 scallbackFlow turns an old-style callback or listener API into a Flow. You use it when values arrive through a callback you register, not from suspending code you call directly.
What is channelFlow { } and how does it differ from the plain flow { } builder?
basics
~10 schannelFlow builds a cold Flow but lets you emit values from several coroutines at once using send(). The plain flow builder only lets you emit from one place, sequentially.
What is the core difference between a Channel and a Flow in Kotlin coroutines, and what does it mean to call a Channel 'hot' and a Flow 'cold'?
basics
~20 sA Channel is like a queue that passes items between coroutines; each item is taken by one receiver. A Flow is a recipe that re-runs from the start for every collector. Channel is hot (always live); Flow is cold (starts when collected).
What is the role of awaitClose { } in callbackFlow, and what happens if you omit it?
basics
~10 sawaitClose keeps the flow alive until it is cancelled or closed, then runs cleanup like unregistering the listener. If you leave it out, the flow ends immediately and Kotlin throws an error.
Why does emitting from a launched coroutine inside flow { } throw an exception, and how does channelFlow solve it?
basics
~20 sflow { } requires that all emit() calls happen in the same coroutine, so emitting from a new coroutine breaks that rule and throws. channelFlow uses a channel and a thread-safe send(), so any coroutine can produce values.
What does the `catch { }` operator do in a Kotlin Flow, and which exceptions can it handle?
basics
~10 scatch runs when something fails earlier in the flow (upstream). It only catches errors from the parts above it, lets you log them, and can send a backup value instead of crashing.
What do the Flow operators onStart and onCompletion do, and when does each block run?
basics
~10 sonStart runs once right before a flow starts producing values. onCompletion runs once after the flow finishes, whether it ended normally, was cancelled, or threw an error.
What does the Flow operator retry(count) do, and where does it sit in a Flow pipeline?
basics
~10 sretry re-subscribes to the flow when it fails with an error, trying again up to the given number of times before letting the error through.
Explain the principle of "exception transparency" in Kotlin Flow. Why is wrapping `emit` in a try/catch a violation?
basics
~20 sException transparency means a flow must let downstream errors flow back out, not swallow them. So you should never put a try/catch around emit, because that would accidentally hide errors that really belong to the collector.
How does retryWhen { cause, attempt -> } work, and what do its parameters mean?
basics
~10 sretryWhen runs a function each time the flow fails. You get the error and how many times it has already retried, and you return true to try again or false to give up.