skip to content

How does asFlow() work for Iterable and Sequence, and when would you use it over flowOf?

level: middleimportance: must knowfreq 50%

answer

  1. asFlow = adapt existing producer to Flow
  2. Overloads: Iterable, Sequence, ranges, functions, arrays
  3. Roughly flow { forEach { emit } }
  4. Sequence one-shot consumed elsewhere can't replay
  5. flowOf = literals; asFlow = existing collection

basics

~20 s

asFlow() 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.

solid answer

~40 s

asFlow() is a set of extension functions that adapt existing producers into a cold Flow. There are overloads for Iterable, Sequence, IntRange/LongRange, and even function types (() -> T and suspend () -> T). For Iterable and Sequence it iterates the source and emits each element in order. Like all cold flows, iteration restarts on every collect(), so an Iterable can be replayed but a single-pass Sequence iterator that's already consumed cannot. Choose asFlow() when values already exist in a collection or are generated by a function; choose flowOf(...) for a small fixed set of literal values. Functionally listOf(1,2,3).asFlow() and flowOf(1,2,3) behave the same, but asFlow expresses 'I have a collection' intent and avoids spreading large collections as varargs.

code

kotlin · 9 lines
kotlin
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    val list = listOf("x", "y", "z")
    list.asFlow().collect { print(it) } // xyz
    println()
    (1..3).asFlow().collect { print(it) } // 123
}

go deeper

for a junior

Knows asFlow converts a list/range into a flow that emits each element.

for a middle

Lists the overloads (Iterable, Sequence, ranges, functions) and explains intent vs flowOf.

for a senior

Reasons about cold re-iteration, one-shot Sequence pitfalls, and the function overloads emitting one value.

for a principal

Weighs API surface trade-offs (varargs vs collection adapters) and the laziness contract across overloads.

## What asFlow is `asFlow()` is a family of **extension functions** in `kotlinx.coroutines.flow` that convert an existing producer into a cold `Flow`. The common overloads: - `Iterable<T>.asFlow()` — e.g. on a `List`, `Set`. - `Sequence<T>.asFlow()`. - `IntRange.asFlow()`, `LongRange.asFlow()` (ranges are `Iterable`, but there are dedicated overloads). - `(() -> T).asFlow()` and `(suspend () -> T).asFlow()` — turn a function into a single-emission flow that calls the function on each collection. - `Array<T>.asFlow()` and primitive-array variants (e.g. `IntArray`). ```kotlin listOf(1, 2, 3).asFlow().collect { println(it) } // 1 2 3 (1..5).asFlow().collect { println(it) } // 1 2 3 4 5 sequenceOf("a", "b").asFlow().collect { println(it) } // a b ``` ## How it emits For `Iterable`/`Sequence`/range, it simply iterates the source and `emit`s each element in order, then completes. Internally it is roughly `flow { forEach { emit(it) } }`. ## Cold + re-iteration caveat Because flows are **cold**, the body re-runs on every `collect`. For an `Iterable` (like `List`) that means it is re-iterated each time — fine. But a `Sequence` backed by a one-shot iterator that has already been consumed elsewhere cannot be replayed; the safe case is a `Sequence` built from a repeatable generator such as `sequence { }` or `generateSequence`. ## Function overloads ```kotlin val f: suspend () -> Int = { computeValue() } f.asFlow().collect { println(it) } // calls computeValue() once per collection, emits result ``` This emits exactly one value: the function's return. ## asFlow vs flowOf - `flowOf(1, 2, 3)` — for a **fixed literal** set, passed as varargs. - `someList.asFlow()` — for values **already in a collection**, avoiding spreading large collections as varargs and expressing intent clearly. They are functionally interchangeable for the same elements but differ in ergonomics and intent.

  • Is listOf(1,2,3).asFlow() different from flowOf(1,2,3) at runtime?
    Behaviorally they emit the same elements in order; the difference is ergonomic/intent — asFlow adapts an existing collection, flowOf takes varargs literals.
  • What does ((): suspend () -> T).asFlow() emit?
    Exactly one value — the result of invoking the function — on each collection.

saying these in an interview costs you the question

  • Claiming asFlow makes the flow hot
  • Thinking asFlow caches values and won't re-iterate on a second collect
  • Trying to asFlow an already-exhausted single-pass Sequence and expecting emissions
  • Believing asFlow exists only for List

context