val name = "Alice"
Immutable variable (inferred)
var age = 30
Mutable variable
val PI: Double = 3.14
Variable with explicit type
const val VERSION = "1.0"
Compile-time constant (top-level/object)
Int Long Float Double Boolean Char String
Built-in types
val msg = "Hello, $name!"
String template
val sum = "Sum: ${a + b}" Template with expression
val text = """Multi-line string"""
Multi-line raw string
if (x > 0) { ... } else if (x == 0) { ... } else { ... } If/else
val result = if (a > b) a else b
If as expression
for (i in 1..10) { ... } Range for loop
for (i in 1..10 step 2) { ... } Range with step
for (i in 10 downTo 1) { ... } Descending range
for (item in list) { ... } For-in loop
list.forEach { println(it) } forEach with implicit it
when (x) {
1 -> ...
in 2..5 -> ...
else -> ...
} When expression (switch)
val name: String? = null
Nullable type
name?.length
Safe call operator
name ?: "unknown"
Elvis operator (null default)
name!!
Not-null assertion (throws if null)
name?.let { println(it) } Execute block if non-null
val len = name?.length ?: 0
Safe call + elvis
fun add(a: Int, b: Int): Int = a + b
Single-expression function
fun greet(name: String) {
println("Hi $name")
} Block function
fun greet(name: String = "World") {} Default parameter
greet(name = "Alice")
Named argument call
fun sum(vararg nums: Int): Int = nums.sum()
Varargs
val multiply = { a: Int, b: Int -> a * b } Lambda expression
fun String.shout() = this.uppercase()
Extension function
inline fun <T> measure(block: () -> T): T = block()
Inline higher-order
class User(val name: String, var age: Int)
Primary constructor
data class User(val id: Int, val name: String)
Data class (equals/hash/toString)
val (id, name) = user
Destructure data class
class User {
init { println("created") }
} Init block
open class Animal class Dog : Animal()
Inheritance (open required)
interface Clickable { fun click() } Interface
sealed class Result
Sealed class (restricted hierarchy)
enum class Color { RED, GREEN, BLUE } Enum class
object Singleton { val config = ... } Object declaration (singleton)
companion object { fun create() = ... } Companion object (static)
val list = listOf(1, 2, 3)
Immutable list
val list = mutableListOf(1, 2, 3)
Mutable list
val map = mapOf("a" to 1, "b" to 2) Immutable map
val set = setOf(1, 2, 3)
Immutable set
list.filter { it > 2 } Filter collection
list.map { it * 2 } Map each element
list.fold(0) { acc, x -> acc + x } Fold (reduce with initial)
list.groupBy { it % 2 } Group by predicate
list.sortedBy { it.name } Sort by key
list.firstOrNull { it > 10 } First matching or null
suspend fun fetch(): String { ... } Suspending function
runBlocking { val x = fetch() } Run coroutine (blocking)
launch { doWork() } Fire-and-forget coroutine
val result = async { fetch() }.await() Async with result
delay(1000)
Non-blocking delay (ms)
withContext(Dispatchers.IO) { file.read() } Switch dispatcher
coroutineScope { launch {...}; launch {...} } Structured concurrency scope
Kotlin Cheat Sheet — Coroutines, Null Safety, Data Classes & Extensions
Kotlin came out of JetBrains in 2011 as a less verbose alternative to Java on the JVM, and Google made it the preferred Android language in 2019; it has since grown to cover null safety, coroutines, data classes, sealed hierarchies and extension functions while staying a thin reskin of the bytecode underneath. The reference below covers 55+ snippets across basics, null safety, functions, classes, collections and coroutines. Most trouble in real code doesn't come from forgetting syntax. It comes from quirks that look ordinary but bite. The `!!` operator turns a nullable into a non-null at the cost of a `NullPointerException` if the value is in fact null. A `lateinit var` only works on non-nullable reference types and throws `UninitializedPropertyAccessException` if read too early. A `when` over a sealed class is exhaustive only when assigned or returned — used as a statement, the compiler silently lets cases through. These are the snippets reached for when wiring exactly that — the safe call chain, the data class destructure, the coroutine scope — without rereading the Kotlin reference each time.
Common pitfalls in Kotlin
A few patterns earn their place on the first screen of any Kotlin file. `val` is the default and `var` is the exception, because most local state never needs to mutate and immutability removes a class of concurrency bug for free. The Elvis operator `name ?: "unknown"` chains naturally after a safe call to produce a non-nullable result without an `if (x == null)` ladder. `data class` generates `equals`, `hashCode`, `toString` and `copy` so domain types stop carrying boilerplate, and destructuring `val (id, name) = user` falls out of that for free. Coroutines belong inside a `coroutineScope` or `viewModelScope` rather than `GlobalScope`, because structured concurrency cancels child jobs when the parent dies — `GlobalScope` leaks. And `Unit` is a real type returned by every function that doesn't declare a return, not the absence of one, which matters when storing a function reference in a generic container. The cheatsheet groups all of this into basics, null safety, functions, classes, collections and coroutines so the right section is one click away.
- 55+ practical Kotlin snippets
- 6 categories from basics to coroutines
- Null safety and safe-call operators
- Data classes, sealed classes, objects
- Coroutines and structured concurrency
- One-click copy to clipboard
Free. No signup. Your inputs stay in your browser. Ads via Google AdSense (consent required).
By Marco B. ·