Kotlindata_classes.kt
Data classes: copy, destructuring, and component functions
data class User(
val id: Int,
val name: String,
val email: String,
val active: Boolean = true
)
fun main() {
val alice = User(1, "Alice", "alice@example.com")
println(alice) // User(id=1, name=Alice, email=alice@example.com, active=true)
// copy: create modified version without mutation
val updated = alice.copy(email = "newalice@example.com", active = false)
println(updated.email) // newalice@example.com
println(alice.email) // alice@example.com — unchanged
// equals: structural comparison (not reference)
val alice2 = User(1, "Alice", "alice@example.com")
println(alice == alice2) // true — content-based
println(alice === alice2) // false — different objects
// Destructuring
val (id, name, email) = alice
println("$name ($email)") // Alice (alice@example.com)
// Destructuring in for loop
val users = listOf(alice, updated)
for ((_, n, e) in users) { // _ ignores id
println("$n: $e")
}
}Kotlinnull_safety.kt
Null safety: ?., ?:, let, and smart casts
fun findUser(id: Int): String? = if (id > 0) "User$id" else null
fun main() {
val name: String? = findUser(1)
// Safe call: returns null if receiver is null
println(name?.length) // 5
println(name?.uppercase()) // USER1
// Elvis operator: default when null
val display = name ?: "Unknown" // "User1"
val empty = findUser(-1) ?: "Anonymous" // "Anonymous"
// Chain: short-circuits at first null
val nested: String? = null
val len = nested?.trim()?.length // null (no exception)
// let: run block only when non-null
name?.let { n ->
println("Processing: $n") // runs
}
findUser(-1)?.let {
println("won't print") // doesn't run
}
// Smart cast: after null check, no ?. needed
if (name != null) {
println(name.length) // name is String here (not String?)
println(name.uppercase())
}
// requireNotNull: fail fast with message
val required: String? = "value"
val notNull: String = requireNotNull(required) { "name is required" }
}Kotlinscope_functions.kt
Scope functions: let, run, apply, also, with
data class Config(var host: String = "", var port: Int = 0, var debug: Boolean = false)
fun main() {
// apply: configure object, returns the object (this inside)
val config = Config().apply {
host = "localhost"
port = 8080
debug = true
}
println(config) // Config(host=localhost, port=8080, debug=true)
// also: side effect (logging/validation), returns the object (it inside)
val validated = config
.also { require(it.port > 0) { "Port must be positive" } }
.also { println("Config validated: $it") }
// let: transform value, returns lambda result (it inside)
val greeting = "Alice"?.let { "Hello, $it!" } ?: "Hello!"
// run: compute value, returns lambda result (this inside)
val summary = config.run {
"Server at $host:$port (debug=$debug)"
}
println(summary)
// with: non-extension version of run — pass object as argument
val description = with(config) {
buildString {
append("Host: $host\n")
append("Port: $port\n")
append("Debug: $debug\n")
}
}
println(description)
}Kotlincollections.kt
Collections: filter, map, groupBy, flatMap
data class Person(val name: String, val age: Int, val city: String)
fun main() {
val people = listOf(
Person("Alice", 30, "Mumbai"),
Person("Bob", 25, "Delhi"),
Person("Carol", 35, "Mumbai"),
Person("Dave", 28, "Bangalore")
)
// filter + map + sorted
val mumbaites = people
.filter { it.city == "Mumbai" }
.sortedBy { it.age }
.map { it.name }
println(mumbaites) // [Alice, Carol]
// groupBy: Map<K, List<V>>
val byCity = people.groupBy { it.city }
byCity.forEach { (city, residents) ->
println("$city: ${residents.map { it.name }}")
}
// associate: build a map
val ageMap = people.associateBy({ it.name }, { it.age })
println(ageMap["Alice"]) // 30
// flatMap: flatten
val hobbies = mapOf("Alice" to listOf("coding","reading"), "Bob" to listOf("gaming"))
val allHobbies = hobbies.values.flatten()
// partition: split into two lists
val (seniors, juniors) = people.partition { it.age >= 30 }
println(seniors.map { it.name }) // [Alice, Carol]
// fold: accumulate
val totalAge = people.fold(0) { acc, p -> acc + p.age }
// zip: pair two collections
val names = listOf("A", "B", "C")
val scores = listOf(1, 2, 3)
val paired = names.zip(scores) // [(A,1),(B,2),(C,3)]
}Kotlinsealed_classes.kt
Sealed classes for typed results
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val code: Int, val message: String) : Result<Nothing>()
data object Loading : Result<Nothing>()
}
fun fetchUser(id: Int): Result<String> = when {
id <= 0 -> Result.Error(400, "Invalid ID")
id > 100 -> Result.Error(404, "User not found")
else -> Result.Success("User$id")
}
fun handleResult(result: Result<String>) {
when (result) {
is Result.Success -> println("Got: ${result.data}")
is Result.Error -> println("Error ${result.code}: ${result.message}")
Result.Loading -> println("Loading...")
// Compiler warns if any case is missing
}
}
// Sealed interface: allows multiple inheritance
sealed interface UiEvent
data class Navigate(val route: String) : UiEvent
data class ShowSnackbar(val message: String) : UiEvent
data object HideKeyboard : UiEvent
fun main() {
handleResult(fetchUser(42)) // Got: User42
handleResult(fetchUser(-1)) // Error 400: Invalid ID
handleResult(Result.Loading) // Loading...
val event: UiEvent = Navigate("/home")
val message = when (event) {
is Navigate -> "Navigating to ${event.route}"
is ShowSnackbar -> "Showing: ${event.message}"
HideKeyboard -> "Hiding keyboard"
}
println(message)
}Kotlinextension_functions.kt
Extension functions and properties
// Extension functions: add methods to existing types without inheritance
fun String.isValidEmail(): Boolean = contains("@") && contains(".")
fun String.truncate(max: Int, suffix: String = "...") =
if (length <= max) this else take(max - suffix.length) + suffix
fun Int.isEven(): Boolean = this % 2 == 0
fun <T> List<T>.second(): T = this[1]
// Extension property
val String.wordCount: Int get() = if (isBlank()) 0 else trim().split(Regex("\\s+")).size
// Nullable receiver extension
fun String?.orEmpty(): String = this ?: ""
// Extension on generic type
fun <T> List<T>.forEachIndexedReversed(action: (Int, T) -> Unit) {
for (i in lastIndex downTo 0) action(i, this[i])
}
fun main() {
println("alice@example.com".isValidEmail()) // true
println("Hello, this is a long string".truncate(15)) // "Hello, this ..."
println(4.isEven()) // true
val words = "Hello Kotlin World"
println(words.wordCount) // 3
val null_str: String? = null
println(null_str.orEmpty()) // ""
listOf("a", "b", "c").forEachIndexedReversed { i, s ->
print("$i:$s ") // 2:c 1:b 0:a
}
// Extension functions resolve statically — not virtual
open class Base
class Derived : Base()
fun Base.greet() = "Base"
fun Derived.greet() = "Derived"
val b: Base = Derived()
println(b.greet()) // "Base" — static dispatch, not "Derived"
}Kotlincoroutines.kt
Coroutines: launch, async, and structured concurrency
import kotlinx.coroutines.*
suspend fun fetchUser(id: Int): String {
delay(100) // non-blocking — frees the thread
return "User$id"
}
suspend fun fetchPosts(userId: String): List<String> {
delay(150)
return listOf("Post1 by $userId", "Post2 by $userId")
}
fun main() = runBlocking {
// Sequential: total ~250ms
val u1 = fetchUser(1)
val p1 = fetchPosts(u1)
println("$u1: $p1")
// Concurrent with async: total ~150ms (both start at once)
val userDeferred = async { fetchUser(2) }
val postsDeferred = async { fetchPosts("User2") }
val u2 = userDeferred.await()
val p2 = postsDeferred.await()
println("$u2: $p2")
// coroutineScope: structured concurrency — cancels children on failure
val result = coroutineScope {
val a = async { fetchUser(3) }
val b = async { fetchUser(4) }
"${a.await()} and ${b.await()}"
}
println(result)
// withContext: switch dispatcher for blocking work
val data = withContext(Dispatchers.IO) {
// Safe to block here — IO thread pool
Thread.sleep(10)
"data from disk"
}
println(data)
}Kotlinflow.kt
Flow: cold streams and StateFlow
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
// Cold flow: producer only runs when collected
fun numbers(): Flow<Int> = flow {
for (i in 1..5) {
delay(100)
emit(i)
}
}
fun main() = runBlocking {
// Collect with operators
numbers()
.filter { it % 2 == 0 }
.map { it * it }
.collect { println(it) } // 4, 16
// StateFlow: hot flow — always has current value
val counter = MutableStateFlow(0)
val job = launch {
counter.collect { println("Counter: $it") } // prints each emission
}
repeat(3) {
delay(100)
counter.value++
}
job.cancel()
// transform: more powerful than map — can emit multiple values
val doubled = numbers()
.transform { value ->
emit(value)
emit(value * 2) // emit twice per input
}
.take(6)
.toList()
println(doubled) // [1, 2, 2, 4, 3, 6]
// catch: error handling in flow
flow<Int> { emit(1); throw RuntimeException("oops") }
.catch { e -> println("Caught: ${e.message}") }
.collect { println(it) }
}Kotlindelegation.kt
Delegation: by lazy, by Delegates, and interface delegation
import kotlin.properties.Delegates
class HeavyResource {
init { println("HeavyResource created") }
fun use() = "using resource"
}
class MyService(private val logger: Logger) : Logger by logger {
// Delegates all Logger methods to logger — no boilerplate
}
interface Logger {
fun log(msg: String)
fun error(msg: String)
}
class ConsoleLogger : Logger {
override fun log(msg: String) = println("[LOG] $msg")
override fun error(msg: String) = println("[ERR] $msg")
}
fun main() {
// by lazy: computed once on first access, then cached
val resource by lazy {
println("Initialising...")
HeavyResource()
}
println("Before access")
println(resource.use()) // "Initialising..." then "using resource"
println(resource.use()) // just "using resource" — already computed
// by Delegates.observable: fire callback on change
var watched by Delegates.observable("initial") { prop, old, new ->
println("${prop.name} changed: $old → $new")
}
watched = "updated" // "watched changed: initial → updated"
// by Delegates.vetoable: reject changes
var positive by Delegates.vetoable(0) { _, _, new -> new >= 0 }
positive = 5 // accepted
positive = -1 // rejected — value stays 5
println(positive) // 5
// Interface delegation
val service = MyService(ConsoleLogger())
service.log("Hello") // [LOG] Hello
}Kotlingenerics.kt
Generics, variance, and reified type parameters
// Generic class with constraint
class SortedList<T : Comparable<T>> {
private val items = mutableListOf<T>()
fun add(item: T) { items.add(item); items.sort() }
fun toList(): List<T> = items.toList()
}
// Covariant: out T — produces T, never consumes
class Box<out T>(val value: T) // Box<String> can be used as Box<Any>
// Contravariant: in T — consumes T, never produces
class Sorter<in T : Comparable<T>> {
fun sort(items: MutableList<T>) = items.sort()
}
// Reified: access type T at runtime in inline functions
inline fun <reified T> List<*>.filterIsInstance(): List<T> =
filter { it is T }.map { it as T }
inline fun <reified T> String.parseAs(): T? = try {
when (T::class) {
Int::class -> toInt() as T
Double::class -> toDouble() as T
else -> null
}
} catch (e: NumberFormatException) { null }
fun main() {
val sorted = SortedList<Int>()
sorted.add(5); sorted.add(2); sorted.add(8)
println(sorted.toList()) // [2, 5, 8]
val mixed: List<Any> = listOf(1, "hello", 2, "world", 3)
val ints: List<Int> = mixed.filterIsInstance()
println(ints) // [1, 2, 3]
val n: Int? = "42".parseAs()
println(n) // 42
}Kotlinstring_templates.kt
String templates, multiline strings, and buildString
fun main() {
val name = "Alice"
val score = 95
// String templates: $variable and ${expression}
println("$name scored $score")
println("$name scored ${score * 2} doubled")
println("${name.uppercase()} — ${if (score >= 90) "Excellent" else "Good"}")
// Triple-quoted multiline string
val json = """
{
"name": "$name",
"score": $score
}
""".trimIndent() // removes leading indentation
println(json)
// Raw string: no escaping needed
val regex = """^\d{3}-\d{4}$""" // no need to escape backslashes
// buildString: efficient string construction
val report = buildString {
appendLine("=== Report ===")
repeat(3) { i -> appendLine(" Item $i: ${i * 10}") }
append("Total: 30")
}
println(report)
// String operations
" hello world ".trim() // "hello world"
"a,b,c,d".split(",") // [a, b, c, d]
listOf("one","two","three").joinToString(" | ") // "one | two | three"
"abc".padStart(6, '0') // "000abc"
}Kotlincompanion_object.kt
Companion objects and object declarations
class Currency private constructor(
val amount: Double,
val code: String
) {
companion object { // like static methods/fields in Java
val USD = Currency(1.0, "USD")
val EUR = Currency(0.92, "EUR")
fun of(amount: Double, code: String): Currency {
require(amount >= 0) { "Amount must be non-negative" }
return Currency(amount, code)
}
// @JvmStatic: makes callable as static from Java
@JvmStatic
fun parse(s: String): Currency {
val (amount, code) = s.split(" ")
return Currency(amount.toDouble(), code)
}
}
operator fun plus(other: Currency): Currency {
require(code == other.code) { "Currency mismatch" }
return Currency(amount + other.amount, code)
}
override fun toString() = "$amount $code"
}
// Object declaration: singleton
object Database {
private var connected = false
fun connect() { connected = true; println("Connected") }
fun isConnected() = connected
}
fun main() {
val price = Currency.of(29.99, "USD")
val tax = Currency.of(2.40, "USD")
println(price + tax) // 32.39 USD
Database.connect()
println(Database.isConnected()) // true
}Kotlindsl_builder.kt
Type-safe DSL builder with lambda with receiver
// Lambda with receiver: T.() -> Unit — enables DSL syntax
@DslMarker annotation class HtmlDsl
@HtmlDsl
class Tag(val name: String) {
private val attrs = mutableMapOf<String, String>()
private val children = mutableListOf<Tag>()
var text: String? = null
fun attr(key: String, value: String) { attrs[key] = value }
fun tag(name: String, init: Tag.() -> Unit): Tag {
val child = Tag(name).apply(init)
children.add(child)
return child
}
fun render(indent: Int = 0): String = buildString {
val pad = " ".repeat(indent)
val attrStr = attrs.entries.joinToString(" ") { (k,v) -> """$k="$v"""" }
append("$pad<$name${if (attrStr.isNotEmpty()) " $attrStr" else ""}>\n")
text?.let { append("$pad $it\n") }
children.forEach { append(it.render(indent + 1)) }
append("$pad</$name>\n")
}
}
fun html(init: Tag.() -> Unit) = Tag("html").apply(init)
fun main() {
val page = html {
tag("head") {
tag("title") { text = "My Page" }
}
tag("body") {
tag("h1") { text = "Hello, Kotlin!" }
tag("p") {
attr("class", "intro")
text = "DSL built with lambdas."
}
}
}
println(page.render())
}Kotlin reference — Kotlin overview · Learn Kotlin
Everything Kotlin in one place — learning paths, reference, playground, and more.
Kotlin Hub →