Learn Kotlin - Collection & Standard Library
Episode 5 of 23

Learn Kotlin - Collection & Standard Library

This episode masters Kotlin collections and the standard library: List, Set, and Map with their collection operations, higher-order functions like map, filter, fold, and flatMap, sequences with lazy evaluation, plus string manipulation and standard utility functions.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

You mastered OOP in episode 4. Now it's time to leverage Kotlin's greatest strength: the standard library with its extremely rich collection API. With the combination of List, Set, Map, and higher-order functions, you can write data transformations that take dozens of lines in Java as a single expression.

Kotlin's standard library is designed functionally: instead of writing manual loops, you express intent with filter, map, and fold. The code becomes declarative, shorter, and easier to test.

Episode 5 will build the habits you use throughout the series — from episode 6 all the way to episode 22.

The Three Main Collections

List, Set, and Map

Kotlin distinguishes read-only and mutable collections: listOf and mutableListOf, setOf and mutableSetOf, mapOf and mutableMapOf. Read-only collections can't be modified, though their contents remain visible:

KotlinList, Set, Map
val daftar = listOf("apel", "pisang", "ceri")
val unik = setOf(1, 1, 2, 3)
val harga = mapOf("kopi" to 15000, "teh" to 8000)
 
println(daftar[0])
println(unik) // [1, 2, 3]
println(harga["kopi"])

setOf automatically removes duplicates, and mapOf stores key-value pairs written with the infix to. Note that these collections are read-only — to add elements, use the mutable variants.

Collection vs Mutable

The important distinction: List and MutableList are two different interfaces. A function accepting List promises not to modify the contents; a function that needs to modify uses MutableList. This discipline makes function contracts clearer and prevents unexpected side effects.

Higher-order Functions

map, filter, and forEach

The most frequently used collection operations are map for transformation and filter for filtering. Both accept a lambda as an argument:

Kotlinmap and filter
val angka = listOf(1, 2, 3, 4, 5, 6)
 
val kuadrat = angka.map { it * it }
val genap = angka.filter { it % 2 == 0 }
 
println(kuadrat) // [1, 4, 9, 16, 25, 36]
println(genap) // [2, 4, 6]

The lambda { it * it } uses the implicit name it for a single element. The filter expression above essentially runs a loop with a clear intent — far more readable than a manual loop. You can test all the examples with kotlinc Koleksi.kt -include-runtime -d koleksi.jar and run the resulting JAR.

fold and flatMap

fold accumulates all elements into a single value starting from a given initial value. flatMap merges transformation results that are collections into one flat list:

Kotlinfold and flatMap
val angka = listOf(1, 2, 3, 4, 5)
 
val total = angka.fold(0) { akumulator, nilai -> akumulator + nilai }
val pasangan = listOf("ab", "cd").flatMap { it.toList() }
 
println(total) // 15
println(pasangan) // [a, b, c, d]

fold(0) uses 0 as the initial value, then the lambda receives the accumulator and the element. flatMap flattens the results — a pattern often used to build lists from one-to-many relationships.

Sequences and Lazy Evaluation

When to Use a Sequence

With a regular collection, each operation immediately creates a new collection. A map then filter chain processes all elements twice and allocates intermediate collections. Sequence solves this with lazy evaluation: elements are processed one by one only when needed:

KotlinSequence for lazy evaluation
val hasil = (1..1_000_000)
    .asSequence()
    .filter { it % 3 == 0 }
    .map { it * it }
    .take(5)
    .toList()
 
println(hasil)

With asSequence(), the filter and map operations wait until take(5) and toList() are called. For large datasets or long operation chains, sequences save allocations and time — a mental yardstick to hold onto from now on.

When Not to Bother

For small collections, sequences actually add overhead. The rule of thumb: use regular collections for small, simple data; switch to sequences for large data, long operation chains, or when taking only a small portion of the results.

String Manipulation and Utility Functions

Frequently Used String Functions

The standard library provides many concise string functions. Some of the most commonly used:

KotlinString manipulation
val teks = "  Kotlin itu Keren  "
 
println(teks.trim())
println(teks.uppercase())
println(teks.lowercase())
println(teks.replace("Keren", "Powerful"))
println("a,b,c".split(","))
println("hello".repeat(3))

trim, uppercase, replace, split, and repeat are part of the string toolbox. There are also contains, startsWith, substringAfter, and removeSuffix that you'll keep encountering in production code.

Utility Functions: take, drop, chunked, zip

Other collection utility functions complete your arsenal:

KotlinCollection utilities
val daftar = (1..10).toList()
 
println(daftar.take(3))       // [1, 2, 3]
println(daftar.drop(7))       // [8, 9, 10]
println(daftar.chunked(3))    // groups of 3
println(daftar.zip(daftar))   // element pairs

take and drop slice from the front, chunked breaks the list into equally sized groups, and zip merges two collections into pairs. Combining these utilities turns processing logic that would normally be long into one-line expressions.

Closing

Episode 5 unlocks the power of collections and the standard library: List, Set, and Map with read-only contracts, higher-order functions like map, filter, fold, and flatMap, sequences for lazy evaluation on large data, and a variety of string and collection utility functions.

The key takeaways:

  • Read-only collections with listOf and mutable ones with mutableListOf.
  • map transforms, filter filters, fold accumulates.
  • flatMap merges transformation results into a flat list.
  • Sequences provide lazy evaluation for large data and long chains.
  • The string library provides trim, split, replace, repeat, and more.
  • Utilities like take, drop, chunked, and zip write concise logic.

In episode 6 we'll discuss null safety and the type system — nullable types and the safe call operator, the elvis operator and non-null assertions, smart casts and type inference, plus inline classes and value classes that make your code null-safe from compilation onward.

Learn Kotlin - Collection & Standard Library | Learn Kotlin