Kotlin Academy · Lesson

Flow Operators: map, filter, transform, and take

Apply intermediate operators to transform and limit Flow emissions.

Lesson 1 of 413 steps

Flow Operators: map, filter, transform, and take is a free Kotlin Academy lesson on CoddyKit. This is lesson 1 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, and your progress syncs across the web and the CoddyKit app. The Kotlin Academy course includes 4 lessons in total.

What Is a Flow?

A Flow is a cold, asynchronous stream. Intermediate operators like map, filter, and transform are lazy — they run only when collected.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun numbers(): Flow<Int> = flow {
    repeat(5) { emit(it + 1) }
}
fun main() = runBlocking {
    numbers().collect { println(it) }
}

map Operator

map transforms each emitted value. It is a 1-to-1 transformation applied lazily.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    (1..5).asFlow()
        .map { it * it }
        .collect { println(it) } // 1 4 9 16 25
}

filter Operator

filter passes only elements matching the predicate, dropping the rest.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    (1..10).asFlow()
        .filter { it % 2 == 0 }
        .collect { println(it) } // 2 4 6 8 10
}

transform Operator

transform is the most general operator: you can emit zero, one, or many values per input element.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    (1..3).asFlow()
        .transform { n ->
            emit("Item $n")
            emit("Done $n")
        }
        .collect { println(it) }
}

take Operator

take(n) takes only the first n elements and cancels the upstream flow after that.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flow {
        repeat(100) { emit(it) }
    }.take(3)
     .collect { println(it) } // 0 1 2
}

takeWhile and dropWhile

takeWhile takes elements while the predicate is true; dropWhile drops until the predicate becomes false.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    (1..10).asFlow()
        .takeWhile { it < 5 }
        .collect { println(it) } // 1 2 3 4

    (1..10).asFlow()
        .dropWhile { it < 5 }
        .collect { println(it) } // 5 6 7 8 9 10
}

Chaining Operators

Operators compose: each operator returns a new Flow, enabling declarative pipelines.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    (1..20).asFlow()
        .filter { it % 3 == 0 }
        .map { it * 2 }
        .take(4)
        .collect { println(it) } // 6 12 18 24
}

mapNotNull

mapNotNull maps and drops null results in one step — equivalent to map + filter { it != null }.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flowOf("1", "two", "3", "four", "5")
        .mapNotNull { it.toIntOrNull() }
        .collect { println(it) } // 1 3 5
}

flatMapConcat

flatMapConcat maps each element to a flow and concatenates the results sequentially.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    (1..3).asFlow()
        .flatMapConcat { n -> flowOf("$n-a", "$n-b") }
        .collect { println(it) }
}

onEach for Side Effects

onEach performs a side effect on each element without changing the stream — good for logging or analytics in a pipeline.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    (1..5).asFlow()
        .onEach { println("Processing: $it") }
        .filter { it % 2 == 0 }
        .collect { println("Collected: $it") }
}

Flow is Cold

Each call to collect restarts the flow from scratch. No element is emitted or transformed until a terminal operator triggers collection.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val flow = (1..3).asFlow().map { println("map $it"); it * 2 }
    println("Before collect")
    flow.collect { println("got $it") }
    println("Second collect:")
    flow.collect { println("got $it") }  // runs again
}

Quick Check

Which operator emits zero, one, or many values per upstream element?

Recap

map transforms 1-to-1; filter drops elements; transform emits any number; take limits count. Chain them declaratively — the flow is cold and only runs when collected.

Free to start

Learn Kotlin with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
51
Lessons
203

Frequently Asked Questions

Is the “Flow Operators: map, filter, transform, and take” lesson free?

Yes — any 3 lessons of the Kotlin Academy learning path, including “Flow Operators: map, filter, transform, and take”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Kotlin Academy course includes 4 lessons in total.

What will I learn in “Flow Operators: map, filter, transform, and take”?

Apply intermediate operators to transform and limit Flow emissions. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 1 of 4.

How long does the “Flow Operators: map, filter, transform, and take” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Flow Operators: map, filter, transform, and take
  2. catch and onCompletion: Error Handling in Flow
  3. combine and zip: Merging Multiple Flows
  4. flowOn and buffer: Context and Backpressure
← Back to Kotlin Academy