liveBook · Manning

Collect

As explained in Kotlin in Action, 2E

collect is a Kotlin Flow terminal operation that suspends while collecting all emitted elements and optionally processes each element with a lambda.

collect is a Kotlin Flow terminal operation: it starts collecting emissions, invokes a lambda for each element, and suspends until the flow finishes or its coroutine scope is cancelled. section 16.2.2 section 17.4

Collect values as they are emitted

fun main() = runBlocking { createValues().collect { value -> log(value) } } The lambda runs once for each emission, so values can be processed immediately instead of waiting for the whole sequence. Because collect suspends, the call runs inside a coroutine such as runBlocking. section 16.1.1 section 16.2.2

The collection and emission steps interleave:

  • Calling collect starts the flow builder. section 16.2.4
  • Each emit invokes the collector lambda and passes it the emitted value. section 16.2.4
  • The collector lambda may suspend, for example while delaying, writing to a database, or making an HTTP request. section 16.2.2
  • After the lambda completes, execution returns to the flow builder until the next emission or completion. section 16.2.4

Intermediate operators such as map, filter, and onEach remain lazy until collect executes the upstream chain. Calling collect again on a cold flow reruns its logic, including side effects such as network requests. section 17.2 section 16.2.2

Use collect() without a lambda when an upstream onEach already performs the per-element work. Unlike first or firstOrNull, collect normally waits for every element; an infinite flow therefore does not complete by itself. section 17.4

Handle exceptions thrown inside the collect lambda with surrounding try-catch. The catch operator handles upstream exceptions only, so downstream failures remain outside its scope. section 18.4.1 section 18.6

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlin.time.Duration.Companion.milliseconds

val letters = flow {
   log("Emitting A!")
   emit("A")
   delay(200.milliseconds)
   log("Emitting B!")
   emit("B")
}

fun main() = runBlocking {
   letters.collect {
       log("Collecting $it")
       delay(500.milliseconds)
   }
}

// 27 [main @coroutine#1] Emitting A!
// 38 [main @coroutine#1] Collecting A
// 757 [main @coroutine#1] Emitting B!
// 757 [main @coroutine#1] Collecting B

Trace timestamps through emission, collection, and suspension to see how the flow builder and collector alternate within one coroutine. section 16.2.2

How Kotlin in Action, 2E covers it

How deep it goes
Explains suspension, cold-flow execution, lambda interleaving, repeated collection, and upstream exception boundaries.
Examples
Uses letters, timed emissions, temperature readings, repeated collection, onEach, and exception recovery with catch.
What it assumes
Assumes familiarity with Kotlin lambdas and coroutines while introducing Flow collection through flow, emit, and runBlocking examples.
What you can do after
Apply it via Kotlin coroutines to process Flow emissions incrementally and perform suspending work for each value.
How it connects
Connects Flow, emit, flow builders, coroutines, intermediate operators, terminal operators, cold flows, and catch.

Also explained in

Compare how 3 books explain collect →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.