A complete quick-reference guide covering all essential Kotlin programming concepts. Includes basic syntax, variables, control flow, functions, collections, classes, null safety, generics, coroutines, and standard library functions. Features practical code examples for every topic. Perfect for beginners learning Kotlin or experienced developers needing a quick syntax reminder.
-
Basic Syntax
- Hello World
- Comments
- Package Definition
-
Variables & Data Types
- Variable Declaration (val vs var)
- Basic Data Types
- Type Inference
- Nullable Types
- Type Conversion
- String Templates
-
Control Flow
- If Expression
- When Expression
- For Loop
- While & Do-While
- Range Expressions
- Break & Continue
-
Functions
- Function Declaration
- Default & Named Arguments
- Single Expression Functions
- Extension Functions
- Infix Functions
- Higher-Order Functions
- Lambda Expressions
- Scope Functions
-
Collections
- Lists
- Sets
- Maps
- Collection Operations
- Filtering & Mapping
-
Classes & Objects
- Class Declaration
- Constructors
- Inheritance
- Abstract Classes
- Interfaces
- Data Classes
- Sealed Classes
- Enum Classes
- Object & Companion Object
-
Properties & Fields
- Property Declaration
- Getters & Setters
- Late Initialization
- Lazy Initialization
-
Null Safety
- Nullable Types
- Safe Call Operator
- Elvis Operator
- Not-Null Assertion
- Safe Casts
-
Generics
- Generic Classes
- Generic Functions
- Variance (in/out)
-
Coroutines
- Basics
- Launch & Async
- Suspending Functions
- Coroutine Context
-
Exception Handling
- Try-Catch
- Try as Expression
-
File I/O
- Reading Files
- Writing Files
-
Common Standard Functions
- let, run, with, apply, also
// Hello World
fun main() {
println("Hello, World!")
}
// Single-line comment
/*
Multi-line comment
*/
// Documentation comment
/**
* @param name User name
*/
// Package definition
package com.example.myapp
// Semicolons are optional
println("No semicolon needed")// Variable Declaration
val immutable = "Cannot change" // Read-only (final in Java)
var mutable = "Can change" // Mutable variable
// Explicit type declaration
val name: String = "Kotlin"
var count: Int = 42
// Basic Data Types
val b: Byte = 127 // 8-bit
val s: Short = 32767 // 16-bit
val i: Int = 2147483647 // 32-bit
val l: Long = 9223372036854775807L // 64-bit
val f: Float = 3.14F // 32-bit floating point
val d: Double = 3.14159265359 // 64-bit floating point
val bool: Boolean = true // true or false
val c: Char = 'A' // Character
val str: String = "Hello" // String
// Type Inference
val inferredInt = 10 // Int
val inferredDouble = 3.14 // Double
val inferredString = "Hello" // String
// Nullable Types
var nullable: String? = null // Can hold null
var nonNullable: String = "Safe" // Cannot hold null
// Type Conversion
val num: Int = 100
val longNum: Long = num.toLong()
val doubleNum: Double = num.toDouble()
val stringNum: String = num.toString()
val charFromInt: Char = 65.toChar() // 'A'
// String Templates
val name = "John"
val age = 30
println("My name is $name")
println("I am ${age} years old")
println("Next year I'll be ${age + 1}")
// Raw Strings (Triple quotes)
val text = """
This is a multiline
string with ${name}
""".trimIndent()// If Expression (returns value)
val max = if (a > b) a else b
val result = if (score >= 90) {
println("Excellent")
"A"
} else if (score >= 80) {
"B"
} else {
"C"
}
// When Expression (replacement for switch)
when (x) {
1 -> println("One")
2, 3 -> println("Two or Three")
in 4..10 -> println("Between 4 and 10")
!in 11..20 -> println("Not between 11 and 20")
is String -> println("It's a string")
else -> println("Otherwise")
}
// When as expression
val grade = when (score) {
in 90..100 -> "A"
in 80..89 -> "B"
in 70..79 -> "C"
in 60..69 -> "D"
else -> "F"
}
// When without argument
when {
x.isOdd() -> println("Odd")
x.isEven() -> println("Even")
}
// For Loop
for (i in 1..5) { } // 1 to 5 inclusive
for (i in 1 until 5) { } // 1 to 4
for (i in 5 downTo 1) { } // 5 to 1
for (i in 1..10 step 2) { } // 1, 3, 5, 7, 9
// Iterating collections
for (item in collection) { }
for ((index, item) in collection.withIndex()) { }
// Iterating maps
for ((key, value) in map) { }
// While Loop
while (condition) {
// code
}
// Do-While Loop
do {
// code
} while (condition)
// Range Expressions
val range1 = 1..10 // 1 to 10 inclusive
val range2 = 1.rangeTo(10)
val range3 = 'a'..'z'
val range4 = 1.0..10.0
// Break & Continue
for (i in 1..10) {
if (i == 3) continue // Skip this iteration
if (i == 7) break // Exit loop
println(i)
}
// Labels for break/continue
outer@ for (i in 1..3) {
inner@ for (j in 1..3) {
if (j == 2) break@outer
println("$i, $j")
}
}// Function Declaration
fun functionName(param1: Type1, param2: Type2): ReturnType {
// body
return value
}
// Examples
fun add(a: Int, b: Int): Int {
return a + b
}
// Unit return type (void)
fun printMessage(msg: String): Unit {
println(msg)
}
// or simply omit Unit
fun printMessage(msg: String) {
println(msg)
}
// Default Arguments
fun greet(name: String = "Guest", greeting: String = "Hello") {
println("$greeting, $name!")
}
greet() // Hello, Guest!
greet("John") // Hello, John!
greet(greeting = "Hi") // Hi, Guest!
// Named Arguments
fun createUser(name: String, age: Int, email: String) { }
createUser(
name = "John",
age = 30,
email = "john@email.com"
)
// Single Expression Functions
fun square(x: Int) = x * x
fun max(a: Int, b: Int) = if (a > b) a else b
// Extension Functions
fun String.addExclamation(): String {
return "$this!"
}
println("Hello".addExclamation()) // Hello!
// Infix Functions
infix fun Int.times(str: String) = str.repeat(this)
println(3 times "Hello ") // Hello Hello Hello
// Varargs
fun sum(vararg numbers: Int): Int {
return numbers.sum()
}
sum(1, 2, 3, 4, 5)
// Higher-Order Functions
fun operate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}
val result = operate(10, 5) { a, b -> a + b }
// Lambda Expressions
val sum = { x: Int, y: Int -> x + y }
val result = sum(5, 3) // 8
// Lambda with receiver
val buildString = StringBuilder().apply {
append("Hello")
append(" ")
append("World")
}
// Function Types
val onClick: () -> Unit = { println("Clicked") }
val sum: (Int, Int) -> Int = { a, b -> a + b }
// Scope Functions
data class Person(var name: String, var age: Int)
val person = Person("John", 30)
// let - execute and return lambda result
val nameLength = person.let { it.name.length }
// run - combination of let and with
val greeting = person.run {
"Hello $name, you are $age years old"
}
// with - non-extension, passes object as argument
with(person) {
println("$name is $age")
}
// apply - returns object itself
val newPerson = Person().apply {
name = "Jane"
age = 25
}
// also - for side effects, returns object
val modifiedPerson = person.also {
println("Name: ${it.name}")
}// Lists
// Immutable List
val immutableList = listOf(1, 2, 3, 4, 5)
val emptyList = emptyList<String>()
// Mutable List
val mutableList = mutableListOf(1, 2, 3, 4, 5)
val arrayList = arrayListOf(1, 2, 3)
// Accessing Elements
val first = immutableList[0] // or immutableList.get(0)
val size = immutableList.size
val contains = 3 in immutableList
// Sets
// Immutable Set
val immutableSet = setOf(1, 2, 3, 3, 4) // [1, 2, 3, 4]
// Mutable Set
val mutableSet = mutableSetOf(1, 2, 3)
val hashSet = hashSetOf(1, 2, 3)
// Maps
// Immutable Map
val immutableMap = mapOf(
"key1" to "value1",
"key2" to "value2",
Pair("key3", "value3")
)
// Mutable Map
val mutableMap = mutableMapOf("a" to 1, "b" to 2)
val hashMap = hashMapOf("a" to 1, "b" to 2)
// Map Operations
val value = immutableMap["key1"]
val valueWithDefault = immutableMap.getOrDefault("key4", "default")
mutableMap["c"] = 3 // Add/Update
// Collection Operations
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// Filtering
val evens = numbers.filter { it % 2 == 0 }
val firstEven = numbers.find { it % 2 == 0 }
val lastEven = numbers.findLast { it % 2 == 0 }
val nonNulls = listOf(1, null, 3).filterNotNull()
// Mapping
val doubled = numbers.map { it * 2 }
val flatMapped = numbers.flatMap { listOf(it, it + 1) }
// Folding/Reducing
val sum = numbers.reduce { acc, num -> acc + num }
val sum2 = numbers.fold(0) { acc, num -> acc + num }
// Checking predicates
val allPositive = numbers.all { it > 0 }
val anyEven = numbers.any { it % 2 == 0 }
val noneNegative = numbers.none { it < 0 }
// Sorting
val sorted = numbers.sorted()
val sortedDesc = numbers.sortedDescending()
val sortedBy = people.sortedBy { it.age }
// Partitioning
val (evens, odds) = numbers.partition { it % 2 == 0 }
// Grouping
val grouped = numbers.groupBy {
if (it % 2 == 0) "even" else "odd"
}
// Other operations
val distinct = listOf(1, 2, 2, 3, 3, 3).distinct()
val count = numbers.count { it > 5 }
val max = numbers.maxOrNull()
val min = numbers.minOrNull()
val sumAll = numbers.sum()
val average = numbers.average()
// Chunking
val chunks = numbers.chunked(3) // [[1,2,3], [4,5,6], [7,8,9], [10]]
// Zipping
val zipped = listOf(1, 2, 3).zip(listOf("a", "b", "c"))
// [(1, "a"), (2, "b"), (3, "c")]// Class Declaration
class Person {
var name: String = ""
var age: Int = 0
}
// Primary Constructor
class Person(firstName: String, lastName: String) {
val fullName = "$firstName $lastName"
}
// Constructor with init block
class Person(val name: String, var age: Int) {
init {
println("Person created: $name, $age")
require(age >= 0) { "Age cannot be negative" }
}
}
// Secondary Constructor
class Person {
var name: String
constructor(name: String) {
this.name = name
}
constructor(firstName: String, lastName: String) {
this.name = "$firstName $lastName"
}
}
// Inheritance (open keyword required)
open class Animal(val name: String) {
open fun makeSound() {
println("Animal sound")
}
}
class Dog(name: String, val breed: String) : Animal(name) {
override fun makeSound() {
super.makeSound() // Call parent
println("Woof!")
}
}
// Abstract Classes
abstract class Shape {
abstract fun area(): Double
fun description() = "This is a shape"
}
class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
}
// Interfaces
interface Drawable {
fun draw()
fun defaultMethod() {
println("Default implementation")
}
}
class Circle : Drawable {
override fun draw() {
println("Drawing circle")
}
}
// Multiple interface implementation
class DrawableCircle : Shape(), Drawable {
override fun area() = 0.0
override fun draw() { }
}
// Data Classes
data class User(
val id: Int,
val name: String,
val email: String
)
// Auto-generates: equals(), hashCode(), toString(), copy(), componentN()
val user1 = User(1, "John", "john@email.com")
val user2 = user1.copy(email = "john.doe@email.com")
val (id, name, email) = user1 // Destructuring
// Sealed Classes
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
}
fun handleResult(result: Result) = when (result) {
is Result.Success -> println(result.data)
is Result.Error -> println(result.message)
Result.Loading -> println("Loading...")
// No else needed because sealed class is exhaustive
}
// Enum Classes
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF);
fun containsRed() = (rgb and 0xFF0000 != 0)
}
// Object (Singleton)
object DatabaseConnection {
var connected: Boolean = false
fun connect() {
connected = true
}
}
// Companion Object
class MyClass {
companion object {
const val CONSTANT = "constant value"
fun create(): MyClass = MyClass()
@JvmStatic
fun staticMethod() {
println("Static method")
}
}
}
MyClass.CONSTANT
MyClass.create()// Property Declaration
class Person {
var name: String = ""
get() = field.uppercase()
set(value) {
field = value.trim()
}
val isAdult: Boolean
get() = age >= 18
var age: Int = 0
private set // Only class can modify
// Backing field
var counter = 0
set(value) {
if (value >= 0) field = value
}
}
// Late Initialization
class Test {
lateinit var subject: String
fun initialize() {
subject = "Kotlin"
}
fun checkInitialized() {
if (::subject.isInitialized) {
println(subject)
}
}
}
// Lazy Initialization
class DataProcessor {
val heavyData: String by lazy {
println("Initializing heavy data...")
"Processed Data"
}
}
// Observable Delegates
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("Initial") {
prop, old, new ->
println("$old -> $new")
}
}
// Vetoable Delegates
var age: Int by Delegates.vetoable(0) {
_, _, new -> new >= 0
}// Nullable Types
var nullableString: String? = null
var nonNullableString: String = "value"
// Safe Call Operator (?.)
val length = nullableString?.length // Returns null if nullableString is null
val upper = nullableString?.uppercase()
// Chaining Safe Calls
data class Address(val city: String?)
data class Person(val address: Address?)
val person: Person? = null
val city = person?.address?.city // Chained safe calls
// Elvis Operator (?:)
val len = nullableString?.length ?: 0
val name = nullableString ?: "Default Name"
// Throw with Elvis
val user = nullableString ?: throw IllegalArgumentException("Name required")
// Not-Null Assertion Operator (!!)
// Use only when you're 100% sure value is not null
val forcedLength = nullableString!!.length // Throws NPE if null
// Safe Casts (as?)
val stringValue: Any = "Hello"
val safeString: String? = stringValue as? String // Returns null if cast fails
// Platform Types (from Java)
// Type! - Use as nullable or non-nullable
// let for null safety
nullableString?.let {
// This block only runs if nullableString is not null
println(it.length)
}
// Collection of nullable elements
val listWithNulls = listOf(1, 2, null, 4, null)
val nonNullList = listWithNulls.filterNotNull()
// Map null handling
val map = mapOf(1 to "one", 2 to null)
val value = map[2] // Nullable String// Generic Class
class Box<T>(val item: T) {
fun getItem(): T = item
}
val intBox = Box(42)
val stringBox = Box("Hello")
// Generic Function
fun <T> singletonList(item: T): List<T> = listOf(item)
fun <T> T.stringify(): String = this.toString()
// Bounded Type Parameters
fun <T : Number> sum(a: T, b: T): Double {
return a.toDouble() + b.toDouble()
}
fun <T : Comparable<T>> max(a: T, b: T): T {
return if (a > b) a else b
}
// Multiple bounds
fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>
where T : CharSequence,
T : Comparable<T> {
return list.filter { it > threshold }.map { it.toString() }
}
// Variance
// out = Covariant (Producer)
interface Producer<out T> {
fun produce(): T
}
// in = Contravariant (Consumer)
interface Consumer<in T> {
fun consume(item: T)
}
// Invariant (no variance annotation)
class Container<T>(var item: T)
// Usage of variance
fun copy(source: Producer<String>, dest: Consumer<in String>) {
dest.consume(source.produce())
}
// Type Erasure & Reified Types
inline fun <reified T> isOfType(value: Any): Boolean {
return value is T
}
println(isOfType<String>("Hello")) // true// Dependencies (build.gradle.kts)
// implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
import kotlinx.coroutines.*
// Basic Coroutine
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
// Coroutine Builders
// runBlocking - Blocks current thread
runBlocking {
// Your coroutine code
}
// launch - Fire and forget
val job = GlobalScope.launch {
// Do work
}
// async - Returns result
val deferred = GlobalScope.async {
// Do work and return result
"Result"
}
val result = deferred.await()
// Structured Concurrency
fun main() = runBlocking {
val job = launch(Dispatchers.Default) {
val result1 = async { fetchData1() }
val result2 = async { fetchData2() }
println("${result1.await()} ${result2.await()}")
}
job.join()
}
// Suspending Functions
suspend fun fetchData(): String {
delay(1000) // Simulate network call
return "Data"
}
// Coroutine Context & Dispatchers
// Dispatchers.Main - UI thread (Android)
// Dispatchers.IO - I/O operations
// Dispatchers.Default - CPU-intensive work
// Dispatchers.Unconfined - Not confined to any thread
launch(Dispatchers.IO) {
// Network or file I/O
}
launch(Dispatchers.Default) {
// Heavy computation
}
// Changing context
launch(Dispatchers.Default) {
val data = fetchData() // Calls suspend function
withContext(Dispatchers.Main) {
// Update UI
}
}
// Cancellation
val job = launch {
repeat(1000) { i ->
println("Job: $i")
delay(500L)
}
}
delay(1300L)
job.cancel() // Cancels the job
job.join() // Waits for completion
// Job Control
val job = launch {
ensureActive() // Check cancellation
// or
yield() // Yield to check cancellation
}
// Timeout
withTimeout(1000L) {
// Will throw TimeoutCancellationException
longRunningOperation()
}
withTimeoutOrNull(1000L) {
// Returns null on timeout
longRunningOperation()
}
// Coroutine Scope
class MyViewModel : CoroutineScope {
private val job = Job()
override val coroutineContext = Dispatchers.Main + job
fun doWork() {
launch {
// Work
}
}
fun onCleared() {
job.cancel() // Cancel all coroutines
}
}// Try-Catch
try {
val result = riskyOperation()
} catch (e: IOException) {
println("IO Exception: ${e.message}")
} catch (e: Exception) {
println("General Exception: ${e.message}")
} finally {
println("Always executed")
}
// Try as Expression
val result = try {
dangerousOperation()
} catch (e: Exception) {
defaultValue
}
// Custom Exception
class MyCustomException(message: String) : Exception(message)
// Throwing Exceptions
throw MyCustomException("Something went wrong")
// The Nothing type
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
// Inline function with try-catch
inline fun <T, R> T.tryOrNull(block: (T) -> R): R? {
return try {
block(this)
} catch (e: Exception) {
null
}
}import java.io.File
import java.io.InputStream
// Reading Files
// Read entire file
val content = File("file.txt").readText()
// Read lines
val lines = File("file.txt").readLines()
// Read using bufferedReader
File("file.txt").bufferedReader().use { reader ->
reader.forEachLine { line ->
println(line)
}
}
// Read with InputStream
val inputStream: InputStream = File("file.txt").inputStream()
val text = inputStream.bufferedReader().use { it.readText() }
// Writing Files
File("output.txt").writeText("Hello, World!")
// Append to file
File("output.txt").appendText("\nNew line")
// Write with PrintWriter
File("output.txt").printWriter().use { writer ->
writer.println("Line 1")
writer.println("Line 2")
}
// Read with forEachLine
File("file.txt").forEachLine { line ->
println(line)
}
// Check file properties
val file = File("file.txt")
val exists = file.exists()
val isFile = file.isFile
val size = file.length()
val name = file.name
val path = file.path// let
// Usage: nullable objects, scope
val result = "text".let {
println(it.length)
it.uppercase()
}
// run
// Usage: object configuration, compute result
val result = "text".run {
println(this.length)
this.uppercase()
}
// with
// Usage: group function calls on an object
val result = with(buildString()) {
append("Hello")
append(" World")
toString()
}
// apply
// Usage: object configuration
val person = Person().apply {
name = "John"
age = 30
}
// also
// Usage: side effects (logging, validation)
val result = "text".also {
println("Processing: $it")
}.uppercase()
// takeIf & takeUnless
val even = 4.takeIf { it % 2 == 0 } // Returns 4
val odd = 4.takeUnless { it % 2 == 0 } // Returns null
// repeat
repeat(5) { index ->
println("This is iteration $index")
}
// use (try-with-resources)
File("file.txt").bufferedReader().use { reader ->
reader.readText()
}
// check & require
fun setAge(age: Int) {
require(age >= 0) { "Age cannot be negative" }
check(age <= 150) { "Age seems unrealistic" }
}
// TODO (platform marker)
fun add(a: Int, b: Int): Int = TODO("Implement addition later")- var = mutable, val = immutable
- ? = nullable, !! = force non-null
- ?.let = execute if not null
- **?: ** = Elvis operator (default value)
- when = switch on steroids
- data class = auto-equals/hashCode/toString
- object = singleton
- companion object = static members
- Extension functions add functionality without inheritance
- Coroutines for async programming
- Scope functions for cleaner code (let, run, with, apply, also)