Chapter 16: Collections – Basics
Collections – Basics in Kotlin — this is the chapter where your programs start handling real-world data like a pro! ☕🚀
Kotlin’s Collections are one of the most beautiful and most used parts of the language. They are type-safe, null-safe, very concise, and much more powerful than Java’s collections.
We’re going to go super slowly, like we’re sitting together in a cozy Bandra café — I’ll explain everything with real-life analogies, complete runnable examples, step-by-step breakdowns, tables, common mistakes, and tons of practical code you can copy-paste and run right now.
Let’s dive in!
1. Why Kotlin Collections Are So Awesome
In Java → you have List, ArrayList, Set, HashSet, Map, HashMap… and you always have to choose mutable versions even when you don’t need to change them.
In Kotlin → you get two families:
- Read-only (immutable) — safe to share, no accidental changes
- Mutable — when you really need to add/remove/change elements
Real-life analogy:
- Read-only collections = a printed book (you can read it, share it, but you can’t write in it)
- Mutable collections = a notebook (you can read it, write in it, erase, add pages…)
Best practice in 2026: Always prefer read-only (List, Set, Map) unless you actually need to modify the collection. This makes your code safer, more predictable, and easier to reason about.
2. The Six Main Collection Interfaces
| Interface | Read-only / Mutable | Allows Duplicates? | Ordered? | Null allowed? | Best Use Case |
|---|---|---|---|---|---|
| List<T> | Read-only | Yes | Yes | Yes | Ordered list (shopping list, playlist) |
| MutableList<T> | Mutable | Yes | Yes | Yes | When you need to add/remove elements |
| Set<T> | Read-only | No | No | Yes | Unique items (tags, user IDs) |
| MutableSet<T> | Mutable | No | No | Yes | When you need to add/remove unique items |
| Map<K, V> | Read-only | Keys unique | No | Yes (keys & values) | Key-value pairs (dictionary, cache) |
| MutableMap<K, V> | Mutable | Keys unique | No | Yes | When you need to add/remove entries |
3. Creating Collections – The Idiomatic Kotlin Way
Kotlin gives you factory functions that are very clean and type-safe.
A. Creating read-only collections
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
fun main() { // List val readOnlyList: List<String> = listOf("Mumbai", "Pune", "Delhi", "Bangalore") // readOnlyList.add("Chennai") // ERROR! Read-only // Set val uniqueNames: Set<String> = setOf("Webliance", "Amit", "Priya", "Webliance") // duplicate ignored println(uniqueNames) // [Webliance, Amit, Priya] // Map val studentMarks: Map<String, Int> = mapOf( "Webliance" to 95, "Amit" to 88, "Priya" to 92 ) println("Webliance's marks: ${studentMarks["Webliance"]}") } |
B. Creating mutable collections
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
fun main() { // Mutable List val shoppingList: MutableList<String> = mutableListOf("Milk", "Eggs", "Bread") shoppingList.add("Butter") shoppingList.remove("Eggs") println(shoppingList) // [Milk, Bread, Butter] // Mutable Set val uniqueIds: MutableSet<Int> = mutableSetOf(101, 102, 101) // duplicate ignored uniqueIds.add(103) println(uniqueIds) // [101, 102, 103] // Mutable Map val employeeSalaries: MutableMap<String, Double> = mutableMapOf( "Amit" to 85000.0, "Priya" to 92000.0 ) employeeSalaries["Rahul"] = 78000.0 println(employeeSalaries) } |
4. Important Differences Between Read-only & Mutable
| Operation | Read-only (List, Set, Map) | Mutable (MutableList, etc.) | Example |
|---|---|---|---|
| Add element | Not allowed | Allowed | mutableList.add(“item”) |
| Remove element | Not allowed | Allowed | mutableList.remove(“item”) |
| Clear collection | Not allowed | Allowed | mutableList.clear() |
| Change element | Not allowed | Allowed | mutableList[0] = “new” |
| Safe to share across threads | Yes (immutable) | No (unless synchronized) | — |
Best practice: Always return List, Set, Map from functions — never expose MutableList, etc. → Prevents accidental modification from outside.
|
0 1 2 3 4 5 6 7 8 9 10 |
fun getCities(): List<String> { // Return read-only val cities = mutableListOf("Mumbai", "Pune") cities.add("Delhi") return cities // Kotlin auto-casts to read-only List } |
5. Quick Recap Table (Your Cheat Sheet)
| Collection Type | Read-only Factory | Mutable Factory | Best Practice |
|---|---|---|---|
| List | listOf() | mutableListOf() | Return List<T>, use MutableList<T> internally |
| Set | setOf() | mutableSetOf() | Prefer setOf() when no changes needed |
| Map | mapOf() | mutableMapOf() | Return Map<K, V>, mutate inside functions |
| Empty collections | emptyList(), emptySet(), emptyMap() | — | Use for empty read-only collections |
6. Common Newbie Mistakes & Fixes
| Mistake | Problem | Fix |
|---|---|---|
| Returning MutableList from function | Caller can modify your internal data | Return List<T> (Kotlin auto-casts) |
| Using listOf() when you need to modify | Compile error when adding/removing | Use mutableListOf() inside function |
| Forgetting to import kotlin.collections.* | Cannot find listOf(), mutableListOf() | Usually auto-imported – but check |
| Thinking val list = mutableListOf() is immutable | val only protects reference, not content | Use listOf() for read-only |
| Using + on mutable collections | Creates new collection (not modifying) | Use add()/remove() on mutable |
7. Homework for You (Let’s Make It Fun!)
- Basic Create a read-only List<String> of your 5 favorite cities → print them using forEach.
- Medium Create a MutableMap<String, Int> of student names → marks → add 3 students → print all using forEach.
- Advanced Write a function fun getUniqueNames(): Set<String> that returns read-only set of names (use setOf()).
- Fun Create a MutableList<String> shopping list → add 5 items → remove one → print final list.
- Challenge Fix this buggy code:
Kotlin0123456789fun getScores(): MutableList<Int> {return mutableListOf(85, 92, 78)}// Why is this bad? How to fix?
You’ve just mastered Kotlin’s beautiful collections system — now you can handle lists, sets, and maps like a pro!
