Kotlin
Kotlin cheat sheet covering syntax, null safety, coroutines, data classes, extensions, and Android development patterns with examples.
Sign in to mark items as known and track your progress.
Sign inGetting Started
Kotlin basics and fundamentals
Variables & Types
Variable declarations and basic types
// Immutable variable (read-only)
val name: String = "Kotlin"
val age = 25 // Type inference
// name = "Java" // Error: Val cannot be reassigned
// Mutable variable
var count = 0
count++ // OK
count = 10 // OK
// Basic types
val byte: Byte = 127
val short: Short = 32767
val int: Int = 2147483647
val long: Long = 9223372036854775807L
val float: Float = 3.14f
val double: Double = 3.141592653589793
val boolean: Boolean = true
val char: Char = 'K'
val string: String = "Hello, Kotlin"String Templates
String interpolation and manipulation
// String templates
val name = "Alice"
val age = 30
val message = "Hello, $name! You are $age years old."
val expression = "Next year you'll be ${age + 1}"
// Multiline strings
val multiline = """
|First line
|Second line
|Third line
""".trimMargin()
val rawString = """
No escaping needed:
\
Preserves formatting
"""
// String operations
val str = "Kotlin"
println(str.length) // 6
println(str.uppercase()) // KOTLIN
println(str[0]) // K
println(str.substring(0, 3)) // KotNull Safety
Kotlin null safety system
Nullable Types
Working with nullable types safely
// Nullable types
var nullable: String? = "Hello"
nullable = null // OK
var nonNull: String = "Hello"
// nonNull = null // Error: Null cannot be assigned
// Safe call operator
val length = nullable?.length // Returns null if nullable is null
// Elvis operator
val lengthOrZero = nullable?.length ?: 0
val message = nullable ?: "Default message"
// Not-null assertion (use sparingly!)
val forceLength = nullable!!.length // Throws NPE if null
// Safe casts
val any: Any = "String"
val str: String? = any as? String // Safe cast
val num: Int? = any as? Int // Returns nullNull Safety Patterns
Advanced null handling patterns
// Scoped functions for null handling
val str: String? = "Hello"
// let - execute block if not null
str?.let {
println("Length: ${it.length}")
}
// also - side effects
str?.also {
println("Processing: $it")
}?.uppercase()
// run - execute block with receiver
val result = str?.run {
println("Running on $this")
length * 2
}
// takeIf / takeUnless
val email = "user@example.com"
val validEmail = email.takeIf { it.contains("@") }
val invalidEmail = email.takeUnless { it.contains("@") }Functions
Function declarations and features
Function Basics
Function syntax and parameters
// Basic function
fun greet(name: String): String {
return "Hello, $name!"
}
// Single expression function
fun add(a: Int, b: Int) = a + b
// Default parameters
fun connect(host: String = "localhost", port: Int = 8080) {
println("Connecting to $host:$port")
}
// Named arguments
connect(port = 3000, host = "example.com")
// Unit return type (void)
fun printMessage(msg: String): Unit {
println(msg)
}
// Unit can be omitted
fun log(msg: String) {
println("[LOG] $msg")
}Higher-Order Functions
Functions as parameters and lambdas
// Lambda expressions
val sum = { x: Int, y: Int -> x + y }
val square: (Int) -> Int = { it * it }
// Higher-order function
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}
val result = calculate(10, 5) { a, b -> a * b }
// Function with receiver
fun buildString(action: StringBuilder.() -> Unit): String {
val sb = StringBuilder()
sb.action()
return sb.toString()
}
val html = buildString {
append("<h1>")
append("Title")
append("</h1>")
}
// Inline functions
inline fun measureTime(block: () -> Unit): Long {
val start = System.currentTimeMillis()
block()
return System.currentTimeMillis() - start
}Classes & Objects
Object-oriented programming in Kotlin
Classes
Class declarations and constructors
// Primary constructor
class Person(val name: String, var age: Int)
// Full syntax with init block
class Student(firstName: String, lastName: String) {
val fullName: String
var grade: Int = 0
init {
fullName = "$firstName $lastName"
println("Student created: $fullName")
}
// Secondary constructor
constructor(name: String) : this(name, "") {
println("Secondary constructor called")
}
}
// Properties with getters/setters
class Temperature {
var celsius: Double = 0.0
get() = field
set(value) {
field = if (value < -273.15) -273.15 else value
}
val fahrenheit: Double
get() = celsius * 9/5 + 32
}Inheritance
Class inheritance and polymorphism
// Open class (can be inherited)
open class Animal(val name: String) {
open fun makeSound() {
println("Some generic animal sound")
}
fun sleep() {
println("$name is sleeping")
}
}
// Inheritance
class Dog(name: String, val breed: String) : Animal(name) {
override fun makeSound() {
println("$name barks: Woof!")
}
fun wagTail() {
println("$name is wagging tail")
}
}
// Abstract classes
abstract class Shape {
abstract val area: Double
abstract fun draw()
fun describe() {
println("Area: $area")
}
}
class Circle(private val radius: Double) : Shape() {
override val area = Math.PI * radius * radius
override fun draw() {
println("Drawing circle with radius $radius")
}
}Data Classes & Objects
Data classes, objects, and companions
Data Classes
Classes for holding data
// Data class
data class User(
val id: Int,
val name: String,
var email: String
)
val user = User(1, "Alice", "alice@example.com")
val copy = user.copy(email = "newemail@example.com")
// Destructuring
val (id, name, email) = user
// Generated methods
println(user.toString()) // User(id=1, name=Alice, email=alice@example.com)
println(user.hashCode())
println(user == copy) // false (different email)
// Data class requirements
// - Primary constructor with at least one parameter
// - All parameters marked as val or var
// - Cannot be abstract, open, sealed, or innerObjects & Companions
Singleton objects and companion objects
// Object declaration (Singleton)
object DatabaseConnection {
init {
println("Initializing database connection")
}
fun connect() {
println("Connecting to database...")
}
}
// Usage
DatabaseConnection.connect()
// Companion object
class Factory {
companion object {
private var counter = 0
fun create(): Factory {
counter++
return Factory()
}
fun getCount() = counter
}
}
val instance = Factory.create()
val count = Factory.getCount()
// Named companion
class MyClass {
companion object Loader {
fun load() = MyClass()
}
}Collections
Lists, Sets, Maps and operations
Collection Types
Lists, Sets, and Maps
// Immutable collections
val list = listOf(1, 2, 3)
val set = setOf("a", "b", "c")
val map = mapOf("key1" to "value1", "key2" to "value2")
// Mutable collections
val mutableList = mutableListOf(1, 2, 3)
mutableList.add(4)
mutableList.removeAt(0)
val mutableSet = mutableSetOf("a", "b")
mutableSet.add("c")
val mutableMap = mutableMapOf<String, Int>()
mutableMap["one"] = 1
mutableMap["two"] = 2
// Array types
val intArray = intArrayOf(1, 2, 3)
val stringArray = arrayOf("a", "b", "c")
val nullArray = arrayOfNulls<String>(5)Collection Operations
Transformations and aggregations
// Transformations
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
val filtered = numbers.filter { it > 2 }
val strings = numbers.map { "Item $it" }
// Aggregations
val sum = numbers.sum()
val average = numbers.average()
val max = numbers.maxOrNull()
val count = numbers.count { it % 2 == 0 }
// Grouping
val words = listOf("apple", "apricot", "banana", "blueberry")
val grouped = words.groupBy { it.first() }
// {a=[apple, apricot], b=[banana, blueberry]}
// Flattening
val nested = listOf(listOf(1, 2), listOf(3, 4))
val flat = nested.flatten() // [1, 2, 3, 4]
val flatMapped = nested.flatMap { it.map { n -> n * 2 } } // [2, 4, 6, 8]Control Flow
Conditionals and loops
Conditionals
if, when, and conditional expressions
// If expression
val max = if (a > b) a else b
// If-else chain
val result = if (score >= 90) {
"A"
} else if (score >= 80) {
"B"
} else if (score >= 70) {
"C"
} else {
"F"
}
// When expression (like switch)
when (x) {
1 -> println("One")
2 -> println("Two")
3, 4 -> println("Three or Four")
in 5..10 -> println("Between 5 and 10")
!in 10..20 -> println("Not between 10 and 20")
is String -> println("It's a string")
else -> println("Unknown")
}
// When as expression
val description = when (val code = getCode()) {
200 -> "OK"
404 -> "Not Found"
500 -> "Server Error"
else -> "Unknown code: $code"
}Loops
for, while, and loop control
// For loops
for (i in 1..5) {
println(i) // 1, 2, 3, 4, 5
}
for (i in 1 until 5) {
println(i) // 1, 2, 3, 4
}
for (i in 5 downTo 1) {
println(i) // 5, 4, 3, 2, 1
}
for (i in 1..10 step 2) {
println(i) // 1, 3, 5, 7, 9
}
// Iterating collections
val list = listOf("a", "b", "c")
for (item in list) {
println(item)
}
for ((index, value) in list.withIndex()) {
println("$index: $value")
}
// While loops
var x = 5
while (x > 0) {
println(x--)
}
// Do-while
do {
val y = readLine()
} while (y != "exit")Extensions
Extension functions and properties
Extension Functions
Adding functions to existing types
// Extension function
fun String.removeSpaces(): String {
return this.replace(" ", "")
}
val text = "Hello World"
println(text.removeSpaces()) // HelloWorld
// Extension properties
val String.lastChar: Char
get() = this[length - 1]
println("Kotlin".lastChar) // n
// Extensions on nullable types
fun String?.isNullOrEmpty(): Boolean {
return this == null || this.isEmpty()
}
val nullString: String? = null
println(nullString.isNullOrEmpty()) // true
// Generic extensions
fun <T> List<T>.secondOrNull(): T? {
return if (size >= 2) this[1] else null
}Scope Functions
let, run, with, apply, also
// let - it as argument, returns result
val result = "Hello".let {
println("Original: $it")
it.uppercase()
} // HELLO
// Null safety with let
val nullableString: String? = "Kotlin"
nullableString?.let {
println("Length: ${it.length}")
}
// run - this as receiver, returns result
val formatted = "hello".run {
println("Original: $this")
uppercase()
} // HELLO
// with - non-extension, returns result
val numbers = mutableListOf(1, 2, 3)
val sum = with(numbers) {
add(4)
add(5)
sum()
}
// apply - this as receiver, returns receiver
val person = Person().apply {
name = "Alice"
age = 30
email = "alice@example.com"
}
// also - it as argument, returns receiver
val list = mutableListOf(1, 2, 3).also {
println("Adding items to list: $it")
it.add(4)
}Coroutines
Asynchronous programming with coroutines
Coroutine Basics
Launching and managing coroutines
// Coroutine scope and launch
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000)
println("World")
}
println("Hello")
}
// Async and await
suspend fun fetchUser(): User {
delay(1000) // Simulated network call
return User("Alice")
}
suspend fun fetchPosts(): List<Post> {
delay(1000)
return listOf(Post("Title"))
}
fun main() = runBlocking {
val user = async { fetchUser() }
val posts = async { fetchPosts() }
println("User: ${user.await()}")
println("Posts: ${posts.await()}")
}
// Suspend functions
suspend fun doWork() {
delay(1000)
println("Work done")
}Coroutine Context
Dispatchers and coroutine context
// Dispatchers
fun main() = runBlocking {
launch(Dispatchers.Main) {
// UI updates (Android)
}
launch(Dispatchers.IO) {
// IO operations
val data = readFile()
}
launch(Dispatchers.Default) {
// CPU-intensive work
val result = complexCalculation()
}
launch(Dispatchers.Unconfined) {
// Not confined to any thread
}
}
// withContext - switching context
suspend fun fetchData(): String = withContext(Dispatchers.IO) {
// Perform IO operation
readFromNetwork()
}
suspend fun processData() = withContext(Dispatchers.Default) {
// CPU-intensive processing
parseData()
}
// Flow - cold asynchronous stream
fun numbersFlow(): Flow<Int> = flow {
for (i in 1..5) {
delay(100)
emit(i)
}
}
fun main() = runBlocking {
numbersFlow()
.map { it * it }
.filter { it % 2 == 0 }
.collect { println(it) }
}Generics
Generic types and variance
Generic Classes & Functions
Type parameters and constraints
// Generic class
class Box<T>(val value: T) {
fun get(): T = value
}
val intBox = Box(42)
val stringBox = Box("Hello")
// Generic function
fun <T> singletonList(item: T): List<T> {
return listOf(item)
}
val list = singletonList("item")
// Multiple type parameters
class Pair<A, B>(val first: A, val second: B) {
fun swap(): Pair<B, A> = Pair(second, first)
}
// Type constraints
fun <T : Comparable<T>> max(a: T, b: T): T {
return if (a > b) a else b
}
// Multiple constraints with where
fun <T> process(value: T)
where T : CharSequence,
T : Comparable<T> {
println("Length: ${value.length}")
println("Value: $value")
}Delegation
Class and property delegation
Delegation Patterns
Class delegation and delegated properties
// Class delegation
interface Base {
fun print()
val message: String
}
class BaseImpl(val x: Int) : Base {
override fun print() = println(x)
override val message = "BaseImpl: $x"
}
class Derived(b: Base) : Base by b {
// Can override members
override val message = "Derived message"
}
val base = BaseImpl(10)
val derived = Derived(base)
derived.print() // Delegates to base
// Delegated properties
class User {
// Lazy property
val lazyValue: String by lazy {
println("Computing lazy value")
"Hello"
}
// Observable property
var name: String by Delegates.observable("Initial") {
prop, old, new ->
println("$old -> $new")
}
// Vetoable property
var age: Int by Delegates.vetoable(0) {
prop, old, new ->
new >= 0 // Reject negative values
}
}DSL Building
Creating domain-specific languages
DSL Construction
Building type-safe DSLs
// HTML DSL example
class HTML {
private val children = mutableListOf<Element>()
fun body(init: Body.() -> Unit) {
val body = Body()
body.init()
children.add(body)
}
}
class Body : Element() {
fun h1(text: String, init: H1.() -> Unit = {}) {
val h1 = H1(text)
h1.init()
children.add(h1)
}
fun p(text: String) {
children.add(P(text))
}
}
fun html(init: HTML.() -> Unit): HTML {
val html = HTML()
html.init()
return html
}
// Usage
val doc = html {
body {
h1("Title") {
// H1 configuration
}
p("Paragraph text")
}
}Annotations & Reflection
Custom annotations and reflection
Annotations
Creating and using annotations
// Annotation declaration
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class MyAnnotation(
val name: String,
val version: Int = 1
)
// Using annotations
@MyAnnotation(name = "Example", version = 2)
class AnnotatedClass {
@Deprecated("Use newMethod instead")
fun oldMethod() {}
@JvmStatic
fun staticMethod() {}
@Throws(IOException::class)
fun riskyMethod() {
throw IOException("Error")
}
}
// Built-in annotations
class Example {
@JvmField
val field = "Public field in Java"
@JvmOverloads
fun method(a: String = "default") {}
@Suppress("UNCHECKED_CAST")
fun uncheckedCast(obj: Any): List<String> {
return obj as List<String>
}
}Interoperability
Java interop and platform types
Java Interop
Calling Java from Kotlin and vice versa
// Calling Java from Kotlin
val list = ArrayList<String>() // Java class
list.add("item")
list.remove("item")
// Platform types
val item = list[0] // Platform type String!
// Can be treated as nullable or non-null
val nullable: String? = item
val nonNull: String = item // May throw NPE
// Java getters/setters as properties
// Java: class Person { getName(); setName(String) }
val person = Person()
person.name = "Alice" // Calls setName
val name = person.name // Calls getName
// Static members
val result = Math.max(5, 10) // Java static method
val pi = Math.PI // Java static field
// SAM conversion
val runnable = Runnable {
println("Running")
}
button.setOnClickListener { view ->
// SAM conversion for Java interfaces
}Advanced Features
Inline classes, contracts, and more
Inline & Value Classes
Performance optimizations
// Inline functions
inline fun measureTimeMillis(block: () -> Unit): Long {
val start = System.currentTimeMillis()
block()
return System.currentTimeMillis() - start
}
// No function call overhead
val time = measureTimeMillis {
// Code is inlined here
Thread.sleep(100)
}
// Inline classes (value classes)
@JvmInline
value class UserId(val id: Long) {
init {
require(id > 0) { "Id must be positive" }
}
val displayId: String
get() = "USER_$id"
}
// No boxing overhead at runtime
fun getUser(userId: UserId) {
// userId is passed as primitive long
}
// Crossinline and noinline
inline fun inlineFunc(
crossinline body: () -> Unit, // Can't use return
noinline callback: () -> Unit // Not inlined
) {
val runnable = object : Runnable {
override fun run() {
body() // OK with crossinline
}
}
callback() // Regular function call
}