Bookmark this page. Use Ctrl+F (or Cmd+F on Mac) to find what you need. This cheat sheet covers Kotlin syntax from basics to coroutines. Try examples live at play.kotlinlang.org.
Last updated: April 2026
Variables Syntax Description val name = "Alex" Immutable (read-only) — cannot reassign var count = 0 Mutable — can reassign val age: Int = 25 Explicit type annotation const val PI = 3.14 Compile-time constant (top-level or object only) val name = "Alex" // type inferred as String var score = 0 // type inferred as Int score = 10 // OK — var can be reassigned // name = "Sam" // ERROR — val cannot be reassigned Basic Types Type Example Notes Int 42 32-bit integer Long 42L 64-bit integer Double 3.14 64-bit decimal Float 3.14f 32-bit decimal Boolean true, false String "hello" Immutable Char 'A' Single character Type Conversions val x: Int = 42 val d: Double = x.toDouble() // 42.0 val s: String = x.toString() // "42" val i: Int = "123".toInt() // 123 val safe: Int? = "abc".toIntOrNull() // null Null Safety Syntax Description String? Nullable type — can hold null name?.length Safe call — returns null if name is null name ?: "default" Elvis operator — use default if null name!! Not-null assertion — throws if null (avoid this) name?.let { ... } Execute block only if not null val name: String? = null val len = name?.length // null (no crash) val safe = name ?: "Unknown" // "Unknown" // val crash = name!!.length // throws NullPointerException String Templates val name = "Alex" println("Hello $name") // Hello Alex println("Length: ${name.length}") // Length: 4 println("Sum: ${2 + 3}") // Sum: 5 Functions // Regular function fun greet(name: String): String { return "Hello $name" } // Single-expression function fun greet(name: String) = "Hello $name" // Default parameters fun greet(name: String = "World") = "Hello $name" // Named arguments greet(name = "Alex") // Unit return type (void equivalent) fun log(message: String) { println(message) } Control Flow if / else (is an expression) val max = if (a > b) a else b when (replaces switch) when (x) { 1 -> println("one") 2, 3 -> println("two or three") in 4..10 -> println("between 4 and 10") is String -> println("it is a string") else -> println("something else") } // Guard conditions in when (Kotlin 2.2+) when (val result = fetchData()) { is Result.Success if result.data.isNotEmpty() -> show(result.data) is Result.Success -> showEmpty() is Result.Error -> showError(result.message) } // when as expression val label = when { score >= 90 -> "A" score >= 80 -> "B" else -> "C" } Loops for (i in 1..5) { } // 1, 2, 3, 4, 5 for (i in 1 until 5) { } // 1, 2, 3, 4 (or 1..<5) for (i in 1..<5) { } // 1, 2, 3, 4 (open-ended range, Kotlin 1.8+) for (i in 5 downTo 1) { } // 5, 4, 3, 2, 1 for (i in 0..10 step 2) { } // 0, 2, 4, 6, 8, 10 for (item in list) { } // iterate a collection list.forEachIndexed { index, item -> } Collections Type Create Mutable Version List listOf(1, 2, 3) mutableListOf(1, 2, 3) Set setOf(1, 2, 3) mutableSetOf(1, 2, 3) Map mapOf("a" to 1) mutableMapOf("a" to 1) Common Operations val numbers = listOf(1, 2, 3, 4, 5) numbers.filter { it > 2 } // [3, 4, 5] numbers.map { it * 2 } // [2, 4, 6, 8, 10] numbers.first() // 1 numbers.last() // 5 numbers.firstOrNull { it > 10 } // null numbers.any { it > 3 } // true numbers.all { it > 0 } // true numbers.count { it % 2 == 0 } // 2 numbers.sum() // 15 numbers.sorted() // [1, 2, 3, 4, 5] numbers.reversed() // [5, 4, 3, 2, 1] numbers.distinct() // remove duplicates numbers.take(3) // [1, 2, 3] numbers.drop(2) // [3, 4, 5] numbers.groupBy { it % 2 } // {1=[1,3,5], 0=[2,4]} numbers.associate { it to it * it } // {1=1, 2=4, 3=9, ...} numbers.flatMap { listOf(it, it * 10) } // [1,10,2,20,...] Map Operations val map = mapOf("a" to 1, "b" to 2) map["a"] // 1 map.getOrDefault("c", 0) // 0 map.keys // [a, b] map.values // [1, 2] map.entries // [a=1, b=2] map + ("c" to 3) // new map with c added Lambdas val double = { x: Int -> x * 2 } double(5) // 10 // Single parameter uses "it" val numbers = listOf(1, 2, 3) numbers.filter { it > 1 } // Trailing lambda numbers.fold(0) { acc, n -> acc + n } Classes // Data class — equals, hashCode, toString, copy generated data class User(val name: String, val age: Int) val user = User("Alex", 25) val copy = user.copy(age = 26) // Enum class enum class Color { RED, GREEN, BLUE } // Sealed class — restricted hierarchy sealed class Result { data class Success(val data: String) : Result() data class Error(val message: String) : Result() data object Loading : Result() } // Object — singleton object Database { fun connect() { } } // Companion object — static-like members class MyClass { companion object { fun create(): MyClass = MyClass() } } Extension Functions fun String.addExclamation() = "$this!" "Hello".addExclamation() // "Hello!" fun List<Int>.secondOrNull(): Int? = if (size >= 2) this[1] else null Scope Functions Function Object ref Return Use case let it Lambda result Null checks, transformations run this Lambda result Object config + compute result with this Lambda result Group calls on an object apply this Object itself Object configuration also it Object itself Side effects (logging, validation) // let — execute block if not null val length = name?.let { it.length } // apply — configure a builder/mutable object val paint = Paint().apply { color = Color.RED strokeWidth = 4f } // also — side effects val list = mutableListOf(1, 2).also { println("Before: $it") } // run — compute a result val result = service.run { connect() fetchData() } // with — group calls val info = with(user) { "$name is $age years old" } Coroutines Basics // Launch — fire and forget scope.launch { val data = fetchData() // suspend function updateUi(data) } // Async — returns a Deferred (future) val deferred = async { fetchData() } val result = deferred.await() // Parallel execution coroutineScope { val a = async { fetchA() } val b = async { fetchB() } println("${a.await()} ${b.await()}") } // Switch context withContext(Dispatchers.IO) { // Run on background thread readFile() } // Flow — reactive stream fun numbers(): Flow<Int> = flow { for (i in 1..3) { delay(100) emit(i) } } // collect is a suspend function — must be called inside a coroutine scope.launch { numbers().collect { println(it) } } Dispatcher Use case Dispatchers.Main UI updates Dispatchers.IO Network, database, file I/O Dispatchers.Default CPU-heavy computation Smart Casts // Kotlin auto-casts after a type check — no explicit cast needed fun printLength(x: Any) { if (x is String) { println(x.length) // x is auto-cast to String } } // Works with when too when (result) { is Result.Success -> println(result.data) is Result.Error -> println(result.message) } Value Classes // Wraps a value with zero runtime overhead (no extra object allocation) @JvmInline value class Email(val address: String) val email = Email("alex@example.com") // At runtime, this is just a String — no wrapper object Multi-line Strings val json = """ { "name": "Alex", "age": 25 } """.trimIndent() val sql = """ SELECT * FROM users WHERE age > 18 ORDER BY name """.trimIndent() Common Patterns Safe casting val x: Any = "hello" val s: String? = x as? String // "hello" val i: Int? = x as? Int // null (no crash) Destructuring val (name, age) = User("Alex", 25) val (key, value) = mapEntry takeIf / takeUnless val positiveNumber = number.takeIf { it > 0 } // number or null val nonBlank = name.takeUnless { it.isBlank() } // name or null // Chain with Elvis val port = config.getPort().takeIf { it in 1..65535 } ?: 8080 Lazy initialization val heavy: String by lazy { println("Computed!") "result" } Common Mistakes Mutable vs immutable collections — listOf() returns a read-only List. Use mutableListOf() if you need add() or remove(). Casting a List to MutableList is unsafe.
...