In Kotlin, Sequence is a lazy sequence that allows you to work efficiently with large or even potentially infinite datasets. Operations on Sequences (like map, filter) are not executed immediately; instead, a chain of actions is built, and computation occurs only when necessary (during a terminal operation, e.g., toList).
Why is this important:
Code example:
val numbers = generateSequence(1) { it + 1 } .filter { it % 2 == 0 } .map { it * it } .take(5) .toList() println(numbers) // [4, 16, 36, 64, 100]
In this example, only the first 5 elements of the sequence will actually be computed, despite it being potentially infinite.
When to use Sequence:
Can you guarantee that operators like
mapandfilteron regular Kotlin collections are also lazy? Why?
Answer: No, standard collection operations (List.map, List.filter, etc.) in Kotlin are strictly eager. Each operation creates an intermediate collection and processes all elements immediately. Laziness is only supported when using Sequence.
Example:
val data = listOf(1,2,3,4) val mapped = data.map { println("Mapping $it"); it * 2 } // Immediately prints all values
History
In a project processing large CSV files (up to a gigabyte on write), the collection was first fully loaded into a List, after which chain map/filter were applied. The application crashed due to OutOfMemory — the problem was resolved by replacing List with Sequence, whose map/filter did not create huge intermediate lists.
History
A backend service for aggregating reports from multiple databases initially accumulated search results in List and then filtered: queries became slow, and GC lags were observed. Replacing it with a generator + Sequence allowed aggregating data on the fly, reducing delays significantly.
History
A migrated Java project used standard Kotlin extensions (map, filter) without switching to Sequence when working with large data streams, believing that the code works lazily like Java 8 streams. The error led to serious memory leaks and sudden production failures.