C
h
i
L
L
u
.
.
.

Kotlin Mastery Guide

Complete guide from basics to advanced Android development

Understanding Kotlin: The Modern Programming Language

Kotlin is a modern, statically-typed programming language developed by JetBrains that runs on the Java Virtual Machine (JVM). It was designed to be fully interoperable with Java while addressing many of Java's limitations and verbosity.

What makes Kotlin revolutionary is its concise syntax, null safety, functional programming features, and excellent tooling support. Google announced Kotlin as an official language for Android development in 2017, solidifying its position in the mobile development ecosystem.

Industry Impact: Kotlin has been adopted by major companies like Google, Netflix, Uber, Pinterest, and Trello. It's not just for Android - Kotlin is used for backend development, web frontend (Kotlin/JS), and native development (Kotlin/Native).

1. Kotlin Basics & Syntax

Getting Started: Your First Kotlin Program

Kotlin combines object-oriented and functional programming features with a concise and expressive syntax. Here's how to get started.
// Hello World in Kotlin
fun main() {
    println("Hello, World!")
}

// Variables and basic types
fun variablesDemo() {
    // Immutable variables (read-only)
    val name = "John"           // Type inferred as String
    val age: Int = 25           // Explicit type declaration
    val height = 1.75           // Double by default
    val isStudent = true        // Boolean
    
    // Mutable variables
    var score = 0
    score = 100                 // Can be reassigned
    
    // Null safety
    var nullableName: String? = null  // Nullable type
    nullableName = "Jane"             // Can assign value
    
    // Safe calls
    val length = nullableName?.length  // Returns null if nullableName is null
    
    // Elvis operator
    val safeLength = nullableName?.length ?: 0  // Default value if null
    
    // Type checking and smart casting
    val obj: Any = "Hello"
    if (obj is String) {
        println(obj.length)  // Smart cast to String
    }
    
    // String templates
    println("Name: $name, Age: $age, Score: $score")
    println("Length of name: ${name.length}")
}

// Basic control flow
fun controlFlowDemo() {
    val x = 10
    val y = 20
    
    // If-else as expression
    val max = if (x > y) x else y
    println("Maximum: $max")
    
    // When expression (enhanced switch)
    val grade = when {
        x >= 90 -> "A"
        x >= 80 -> "B"
        x >= 70 -> "C"
        else -> "F"
    }
    
    // Ranges
    for (i in 1..5) {
        print("$i ")  // Output: 1 2 3 4 5
    }
    
    for (i in 5 downTo 1 step 2) {
        print("$i ")  // Output: 5 3 1
    }
    
    // While loops
    var i = 0
    while (i < 5) {
        println("i = $i")
        i++
    }
}

Data Types and Type System

Kotlin has a robust type system with both primitive and reference types, all treated as objects. Understanding the type system is crucial for writing safe and efficient code.
// Basic data types
fun dataTypesDemo() {
    // Numbers
    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
    
    // Characters and strings
    val char: Char = 'A'
    val string: String = "Hello Kotlin"
    val rawString = """
        This is a raw string
        It can span multiple lines
        Without escape characters
    """.trimIndent()
    
    // Arrays
    val numbers = arrayOf(1, 2, 3, 4, 5)
    val squares = Array(5) { i -> (i + 1) * (i + 1) }
    
    // Primitive type arrays (for performance)
    val intArray = intArrayOf(1, 2, 3)
    val charArray = charArrayOf('a', 'b', 'c')
    
    // Type conversions
    val stringNumber = "123"
    val intValue = stringNumber.toInt()
    val doubleValue = stringNumber.toDouble()
    
    // Any type (root of Kotlin class hierarchy)
    val anyValue: Any = "Can be any type"
    
    // Unit type (similar to void)
    fun doSomething(): Unit {  // Unit return type can be omitted
        println("Doing something")
    }
    
    // Nothing type (function never returns)
    fun fail(message: String): Nothing {
        throw IllegalArgumentException(message)
    }
}

// Null safety in depth
fun nullSafetyDemo() {
    // Regular types are non-nullable by default
    var name: String = "John"  // Cannot be null
    
    // Nullable types
    var nullableName: String? = null
    
    // Safe call operator
    val length1 = nullableName?.length  // Returns Int?
    
    // Elvis operator with throw
    val length2 = nullableName?.length ?: throw IllegalArgumentException("Name cannot be null")
    
    // Safe cast
    val obj: Any = "Hello"
    val stringObj = obj as? String  // Returns null if cast fails
    
    // Not-null assertion (use carefully!)
    val forcedLength = nullableName!!.length  // Throws NPE if null
    
    // let function for null checks
    nullableName?.let { 
        println("Name is $it and length is ${it.length}")
    }
    
    // also function for additional operations
    val result = "Hello".also {
        println("Original value: $it")
    }
}

// Strings and text processing
fun stringOperations() {
    val text = "Kotlin Programming"
    
    // Basic operations
    println(text.length)           // 18
    println(text.uppercase())      // "KOTLIN PROGRAMMING"
    println(text.lowercase())      // "kotlin programming"
    println(text.substring(0, 6))  // "Kotlin"
    
    // String templates
    val language = "Kotlin"
    val version = 1.9
    println("Welcome to $language version $version")
    println("2 + 2 = ${2 + 2}")
    
    // Multiline strings
    val html = """
        <html>
            <body>
                <h1>Welcome to Kotlin</h1>
            </body>
        </html>
    """.trimIndent()
    
    // String builders
    val builder = StringBuilder()
    builder.append("Hello")
          .append(" ")
          .append("Kotlin")
    val result = builder.toString()
    
    // Regular expressions
    val regex = Regex("""d+""")  // Raw string for regex
    val hasDigits = regex.containsMatchIn("abc123")
    val digits = regex.findAll("abc123def456").map { it.value }.toList()
}

Control Flow and Expressions

Kotlin treats many constructs as expressions rather than statements, making the code more concise and expressive.
// If expressions
fun ifExpressions(x: Int, y: Int) {
    // Traditional if-else
    if (x > y) {
        println("x is greater")
    } else {
        println("y is greater or equal")
    }
    
    // If as expression
    val max = if (x > y) x else y
    val result = if (x > y) {
        "x is greater"
    } else if (x < y) {
        "y is greater"
    } else {
        "x and y are equal"
    }
}

// When expression (powerful switch replacement)
fun whenExpressions(value: Any) {
    // When with argument
    when (value) {
        1 -> println("One")
        2 -> println("Two")
        3, 4 -> println("Three or Four")  // Multiple values
        in 5..10 -> println("Between 5 and 10")  // Range check
        is String -> println("It's a string with length ${value.length}")  // Type check
        else -> println("Something else")
    }
    
    // When without argument (like if-else chain)
    val score = 85
    val grade = when {
        score >= 90 -> "A"
        score >= 80 -> "B"
        score >= 70 -> "C"
        score >= 60 -> "D"
        else -> "F"
    }
    
    // When with function return
    fun describe(obj: Any): String = when (obj) {
        1 -> "One"
        "Hello" -> "Greeting"
        is Long -> "Long"
        !is String -> "Not a string"
        else -> "Unknown"
    }
}

// Loops and iterations
fun loopExamples() {
    // For loops with ranges
    for (i in 1..5) print("$i ")  // 1 2 3 4 5
    println()
    
    for (i in 1 until 5) print("$i ")  // 1 2 3 4
    println()
    
    for (i in 5 downTo 1) print("$i ")  // 5 4 3 2 1
    println()
    
    for (i in 1..10 step 2) print("$i ")  // 1 3 5 7 9
    println()
    
    // Iterating over arrays and lists
    val names = listOf("Alice", "Bob", "Charlie")
    for (name in names) {
        println(name)
    }
    
    for (index in names.indices) {
        println("Name at $index is ${names[index]}")
    }
    
    for ((index, name) in names.withIndex()) {
        println("Name at $index is $name")
    }
    
    // While and do-while
    var x = 5
    while (x > 0) {
        println(x)
        x--
    }
    
    var y = 0
    do {
        println("y = $y")
        y++
    } while (y < 5)
    
    // Break and continue with labels
    outer@ for (i in 1..3) {
        inner@ for (j in 1..3) {
            if (i == 2 && j == 2) break@outer
            println("i=$i, j=$j")
        }
    }
}

// Exception handling
fun exceptionHandling() {
    // Try-catch as expression
    val number = try {
        "123".toInt()
    } catch (e: NumberFormatException) {
        0  // Default value
    }
    
    // Multiple catch blocks
    try {
        val result = 10 / 0
    } catch (e: ArithmeticException) {
        println("Arithmetic error: ${e.message}")
    } catch (e: Exception) {
        println("General error: ${e.message}")
    } finally {
        println("This always executes")
    }
    
    // Custom exceptions
    class ValidationException(message: String) : Exception(message)
    
    fun validateAge(age: Int) {
        if (age < 0) {
            throw ValidationException("Age cannot be negative")
        }
    }
}

Basic I/O and Console Applications

Kotlin provides simple and intuitive ways to handle input/output operations for console applications.
// Basic input/output operations
fun ioOperations() {
    // Output
    print("Hello")           // No newline
    println("World")         // With newline
    
    // String formatting
    val name = "Alice"
    val age = 30
    println("Name: %s, Age: %d".format(name, age))
    println("Name: $name, Age: $age")  // String templates
    
    // Input from console
    print("Enter your name: ")
    val userName = readLine()  // Returns String?
    
    print("Enter your age: ")
    val userAge = readLine()?.toIntOrNull() ?: 0
    
    println("Hello $userName, you are $userAge years old!")
    
    // File operations (basic)
    import java.io.File
    
    // Reading from file
    val file = File("data.txt")
    if (file.exists()) {
        val content = file.readText()
        println("File content: $content")
        
        // Reading line by line
        file.forEachLine { line ->
            println("Line: $line")
        }
    }
    
    // Writing to file
    val outputFile = File("output.txt")
    outputFile.writeText("Hello Kotlin!\n")
    outputFile.appendText("Another line\n")
}

// Simple console application example
fun calculator() {
    while (true) {
        println("=== Simple Calculator ===")
        println("1. Add")
        println("2. Subtract")
        println("3. Multiply")
        println("4. Divide")
        println("5. Exit")
        print("Choose operation: ")
        
        val choice = readLine()?.toIntOrNull()
        
        if (choice == 5) {
            println("Goodbye!")
            break
        }
        
        if (choice !in 1..4) {
            println("Invalid choice!")
            continue
        }
        
        print("Enter first number: ")
        val num1 = readLine()?.toDoubleOrNull()
        print("Enter second number: ")
        val num2 = readLine()?.toDoubleOrNull()
        
        if (num1 == null || num2 == null) {
            println("Invalid numbers!")
            continue
        }
        
        val result = when (choice) {
            1 -> num1 + num2
            2 -> num1 - num2
            3 -> num1 * num2
            4 -> if (num2 != 0.0) num1 / num2 else "Cannot divide by zero"
            else -> "Invalid operation"
        }
        
        println("Result: $result\n")
    }
}

// Number guessing game
fun guessingGame() {
    val randomNumber = (1..100).random()
    var attempts = 0
    var guessed = false
    
    println("Welcome to the Number Guessing Game!")
    println("I'm thinking of a number between 1 and 100.")
    
    while (!guessed && attempts < 10) {
        print("Enter your guess: ")
        val guess = readLine()?.toIntOrNull()
        
        if (guess == null) {
            println("Please enter a valid number!")
            continue
        }
        
        attempts++
        
        when {
            guess < randomNumber -> println("Too low!")
            guess > randomNumber -> println("Too high!")
            else -> {
                println("Congratulations! You guessed the number in $attempts attempts!")
                guessed = true
            }
        }
    }
    
    if (!guessed) {
        println("Game over! The number was $randomNumber")
    }
}

2. Functions & Object-Oriented Programming

Functions and Functional Programming

Kotlin supports both object-oriented and functional programming paradigms. Functions are first-class citizens and can be treated as values.
// Basic function syntax
fun greet(name: String): String {
    return "Hello, $name!"
}

// Single-expression functions
fun square(x: Int): Int = x * x

// Function with default parameters
fun createMessage(
    name: String,
    title: String = "Mr./Ms.",
    punctuation: String = "!"
): String {
    return "Hello, $title $name$punctuation"
}

// Function with varargs
fun sum(vararg numbers: Int): Int {
    return numbers.sum()
}

// Higher-order functions
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
    return operation(x, y)
}

// Lambda expressions
val multiply = { x: Int, y: Int -> x * y }

// Function types
typealias Arithmetic = (Int, Int) -> Int

// Extension functions
fun String.addExcitement(): String = this + "!!!"

// Infix functions
infix fun Int.times(str: String) = str.repeat(this)

// Function examples in action
fun functionExamples() {
    // Basic function calls
    println(greet("Alice"))  // Hello, Alice!
    println(square(5))       // 25
    
    // Default parameters
    println(createMessage("Bob"))                    // Hello, Mr./Ms. Bob!
    println(createMessage("Charlie", "Dr."))         // Hello, Dr. Charlie!
    println(createMessage("Diana", punctuation = "?")) // Hello, Mr./Ms. Diana?
    
    // Varargs
    println(sum(1, 2, 3, 4, 5))  // 15
    
    // Higher-order functions
    val result1 = calculate(10, 5) { a, b -> a + b }  // 15
    val result2 = calculate(10, 5, multiply)          // 50
    
    // Extension function
    println("Hello".addExcitement())  // Hello!!!
    
    // Infix function
    println(3 times "Hi ")  // Hi Hi Hi 
}

// Tail recursion for optimized recursion
tailrec fun factorial(n: Int, accumulator: Int = 1): Int {
    return if (n <= 1) accumulator else factorial(n - 1, n * accumulator)
}

// Inline functions for performance
inline fun measureTime(block: () -> Unit): Long {
    val start = System.currentTimeMillis()
    block()
    return System.currentTimeMillis() - start
}

// Function scope and visibility
class MathUtils {
    // Public by default
    fun add(a: Int, b: Int) = a + b
    
    // Private function
    private fun validateInput(x: Int) = x > 0
    
    // Protected function
    protected fun internalCalc() = 42
    
    // Local function
    fun complexCalculation(x: Int, y: Int): Int {
        fun validate(num: Int): Boolean = num > 0
        
        return if (validate(x) && validate(y)) x + y else 0
    }
}

Classes and Objects

Kotlin provides concise syntax for defining classes and creating objects, with features like primary constructors, data classes, and sealed classes.
// Basic class definition
class Person(
    val name: String,        // Read-only property
    var age: Int,            // Mutable property
    val city: String = "Unknown"  // Default value
) {
    // Secondary constructor
    constructor(name: String) : this(name, 0)
    
    // Properties with custom getters/setters
    var email: String = ""
        set(value) {
            field = value.lowercase()
        }
    
    val isAdult: Boolean
        get() = age >= 18
    
    // Methods
    fun introduce() {
        println("Hello, I'm $name, $age years old from $city")
    }
    
    // Companion object (static members)
    companion object {
        const val SPECIES = "Homo sapiens"
        
        fun createBaby(name: String): Person {
            return Person(name, 0)
        }
    }
}

// Data classes (automatically generated methods)
data class User(
    val id: Int,
    val username: String,
    val email: String,
    val createdAt: String = ""
) {
    // Custom methods can be added
    fun displayInfo() = "$username ($email)"
}

// Enum classes
enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF);
    
    fun containsRed() = (this.rgb and 0xFF0000) != 0
}

// Sealed classes for restricted hierarchies
sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Error(val message: String) : Result<Nothing>()
    object Loading : Result<Nothing>()
}

// Object expressions and declarations
interface ClickListener {
    fun onClick()
}

// Object expression (anonymous class)
val clickListener = object : ClickListener {
    override fun onClick() {
        println("Button clicked!")
    }
}

// Object declaration (singleton)
object DatabaseManager {
    private var connectionCount = 0
    
    fun connect() {
        connectionCount++
        println("Connected to database. Total connections: $connectionCount")
    }
    
    fun disconnect() {
        if (connectionCount > 0) connectionCount--
        println("Disconnected from database. Remaining connections: $connectionCount")
    }
}

// Class usage examples
fun classExamples() {
    // Creating objects
    val person1 = Person("Alice", 25, "New York")
    val person2 = Person("Bob")  // Using secondary constructor
    
    // Accessing properties
    println(person1.name)  // Alice
    person1.age = 26       // Modifying property
    person1.introduce()    // Hello, I'm Alice, 26 years old from New York
    
    // Data class usage
    val user1 = User(1, "john_doe", "john@example.com")
    val user2 = user1.copy(username = "john_updated")  // Copy with changes
    
    println(user1)         // Automatically generated toString()
    println(user1 == user2) // Automatically generated equals()
    
    // Enum usage
    val color = Color.RED
    println(color.name)        // RED
    println(color.ordinal)     // 0
    println(color.containsRed()) // true
    
    // Sealed class usage
    fun handleResult(result: Result<String>) {
        when (result) {
            is Result.Success -> println("Data: ${result.data}")
            is Result.Error -> println("Error: ${result.message}")
            Result.Loading -> println("Loading...")
        }
    }
    
    // Singleton usage
    DatabaseManager.connect()
    DatabaseManager.connect()
    DatabaseManager.disconnect()
}

Inheritance and Interfaces

Kotlin supports inheritance and interface implementation with modern features like delegation and default interface methods.
// Open classes (Kotlin classes are final by default)
open class Animal(val name: String, val age: Int) {
    open fun makeSound() {
        println("Some generic animal sound")
    }
    
    fun sleep() {
        println("$name is sleeping")
    }
}

// Inheritance
class Dog(name: String, age: Int, val breed: String) : Animal(name, age) {
    override fun makeSound() {
        println("Woof! Woof!")
    }
    
    fun fetch() {
        println("$name is fetching the ball")
    }
}

// Abstract classes
abstract class Shape(val name: String) {
    abstract fun area(): Double
    abstract fun perimeter(): Double
    
    fun displayInfo() {
        println("Shape: $name, Area: ${area()}, Perimeter: ${perimeter()}")
    }
}

class Circle(val radius: Double) : Shape("Circle") {
    override fun area(): Double = Math.PI * radius * radius
    override fun perimeter(): Double = 2 * Math.PI * radius
}

class Rectangle(val width: Double, val height: Double) : Shape("Rectangle") {
    override fun area(): Double = width * height
    override fun perimeter(): Double = 2 * (width + height)
}

// Interfaces with default implementations
interface Drawable {
    fun draw()
    fun erase() {
        println("Erasing the drawing")
    }
}

interface Colorable {
    var color: String
    fun fillColor() {
        println("Filling with $color")
    }
}

// Multiple interface implementation
class Square(val side: Double) : Shape("Square"), Drawable, Colorable {
    override var color: String = "Black"
    
    override fun area(): Double = side * side
    override fun perimeter(): Double = 4 * side
    
    override fun draw() {
        println("Drawing a square with side $side")
    }
    
    // Override default interface method
    override fun fillColor() {
        println("Filling square with $color")
    }
}

// Interface delegation
interface Repository {
    fun getData(): String
}

class DatabaseRepository : Repository {
    override fun getData(): String = "Data from database"
}

class CachedRepository(private val repository: Repository) : Repository by repository {
    private var cachedData: String? = null
    
    override fun getData(): String {
        if (cachedData == null) {
            cachedData = repository.getData()
            println("Data cached")
        }
        return cachedData!!
    }
}

// Inheritance examples
fun inheritanceExamples() {
    // Basic inheritance
    val dog = Dog("Buddy", 3, "Golden Retriever")
    dog.makeSound()  // Woof! Woof!
    dog.sleep()      // Buddy is sleeping
    dog.fetch()      // Buddy is fetching the ball
    
    // Polymorphism
    val animal: Animal = Dog("Max", 2, "Labrador")
    animal.makeSound()  // Woof! Woof! (dynamic dispatch)
    
    // Abstract class usage
    val circle = Circle(5.0)
    val rectangle = Rectangle(4.0, 6.0)
    
    circle.displayInfo()    // Shape: Circle, Area: 78.54, Perimeter: 31.42
    rectangle.displayInfo() // Shape: Rectangle, Area: 24.0, Perimeter: 20.0
    
    // Multiple interface implementation
    val square = Square(4.0)
    square.color = "Blue"
    square.draw()       // Drawing a square with side 4.0
    square.fillColor()  // Filling square with Blue
    square.displayInfo() // Shape: Square, Area: 16.0, Perimeter: 16.0
    
    // Interface delegation
    val repository = CachedRepository(DatabaseRepository())
    println(repository.getData())  // Data from database (with caching)
    println(repository.getData())  // Data from database (from cache)
}

Properties and Delegates

Kotlin properties are more powerful than traditional fields, with built-in support for delegation, lazy initialization, and observable properties.
// Property delegation examples
import kotlin.properties.Delegates
import kotlin.reflect.KProperty

// Custom delegate
class RangeDelegate(private val min: Int, private val max: Int) {
    private var value: Int = min
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
        return value
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: Int) {
        if (newValue in min..max) {
            value = newValue
        } else {
            throw IllegalArgumentException("Value must be between $min and $max")
        }
    }
}

class Product {
    // Lazy initialization
    val expensiveValue: String by lazy {
        println("Computing expensive value...")
        "Expensive Result"
    }
    
    // Observable property
    var price: Double by Delegates.observable(0.0) { prop, old, new ->
        println("Price changed from $old to $new")
    }
    
    // Vetoable property (can reject changes)
    var quantity: Int by Delegates.vetoable(0) { prop, old, new ->
        new >= 0  // Only allow non-negative quantities
    }
    
    // Custom delegate
    var rating: Int by RangeDelegate(1, 5)
    
    // Late initialization
    lateinit var name: String
    
    fun initializeName() {
        name = "Product Name"
    }
    
    fun checkInitialization() {
        if (::name.isInitialized) {
            println("Name is initialized: $name")
        } else {
            println("Name is not initialized")
        }
    }
}

// Built-in delegates examples
fun delegateExamples() {
    val product = Product()
    
    // Lazy delegate
    println(product.expensiveValue)  // Computing expensive value... Expensive Result
    println(product.expensiveValue)  // Expensive Result (cached)
    
    // Observable delegate
    product.price = 19.99  // Price changed from 0.0 to 19.99
    product.price = 15.99  // Price changed from 19.99 to 15.99
    
    // Vetoable delegate
    product.quantity = 10  // Allowed
    println("Quantity: ${product.quantity}")  // 10
    
    product.quantity = -5  // Rejected (remains 10)
    println("Quantity: ${product.quantity}")  // 10
    
    // Custom delegate
    product.rating = 4     // Allowed
    println("Rating: ${product.rating}")  // 4
    
    try {
        product.rating = 6  // Throws IllegalArgumentException
    } catch (e: IllegalArgumentException) {
        println("Error: ${e.message}")
    }
    
    // Lateinit
    product.checkInitialization()  // Name is not initialized
    product.initializeName()
    product.checkInitialization()  // Name is initialized: Product Name
}

// Map delegation
class Config(map: Map<String, Any?>) {
    val serverUrl: String by map
    val port: Int by map
    val timeout: Long by map
}

fun mapDelegationExample() {
    val configMap = mapOf(
        "serverUrl" to "https://api.example.com",
        "port" to 8080,
        "timeout" to 30000L
    )
    
    val config = Config(configMap)
    println("Server: ${config.serverUrl}")  // https://api.example.com
    println("Port: ${config.port}")         // 8080
    println("Timeout: ${config.timeout}")   // 30000
}

// Property delegation for caching
class CacheDelegate<T> {
    private var value: T? = null
    private var computed = false
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        if (!computed) {
            throw IllegalStateException("Value not computed yet")
        }
        return value!!
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
        value = newValue
        computed = true
    }
}

class DataProcessor {
    var processedData: String by CacheDelegate()
    
    fun processData(data: String) {
        // Simulate expensive processing
        processedData = "PROCESSED: $data"
    }
}

3. Collections & Functional Programming

Collections Framework

Kotlin provides a rich collections framework with both mutable and immutable collections, and extensive functional operations.
// Collection types and creation
fun collectionTypes() {
    // Lists
    val immutableList = listOf("apple", "banana", "orange")
    val mutableList = mutableListOf("red", "green", "blue")
    
    // Sets
    val immutableSet = setOf(1, 2, 3, 2, 1)  // Duplicates removed: [1, 2, 3]
    val mutableSet = mutableSetOf("a", "b", "c")
    
    // Maps
    val immutableMap = mapOf(
        "name" to "John",
        "age" to 30,
        "city" to "New York"
    )
    val mutableMap = mutableMapOf<String, Any>()
    
    // Arrays vs Lists
    val array = arrayOf(1, 2, 3)      // Array - fixed size, primitive-friendly
    val list = listOf(1, 2, 3)        // List - read-only interface
    val mutable = mutableListOf(1, 2, 3) // MutableList - can modify
    
    // Empty collections
    val emptyList = emptyList<String>()
    val emptySet = emptySet<Int>()
    val emptyMap = emptyMap<String, Any>()
    
    // Collection builders
    val builtList = buildList {
        add("first")
        addAll(listOf("second", "third"))
        if (true) add("conditional")
    }
}

// Basic collection operations
fun basicOperations() {
    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    val names = listOf("Alice", "Bob", "Charlie", "Diana", "Eve")
    
    // Filtering
    val evenNumbers = numbers.filter { it % 2 == 0 }           // [2, 4, 6, 8, 10]
    val longNames = names.filter { it.length > 4 }             // [Alice, Charlie]
    val notEve = names.filterNot { it == "Eve" }               // All except Eve
    val (even, odd) = numbers.partition { it % 2 == 0 }        // Pair of lists
    
    // Transformation
    val squares = numbers.map { it * it }                      // [1, 4, 9, ...]
    val nameLengths = names.map { it.length }                  // [5, 3, 7, 5, 3]
    val indexed = names.mapIndexed { index, name -> "$index: $name" }
    
    // Sorting
    val sortedNames = names.sorted()                           // Alphabetical
    val sortedByLength = names.sortedBy { it.length }          // By length
    val descending = numbers.sortedDescending()                // [10, 9, 8, ...]
    
    // Aggregation
    val sum = numbers.sum()                                    // 55
    val average = numbers.average()                            // 5.5
    val max = numbers.maxOrNull()                              // 10
    val min = numbers.minOrNull()                              // 1
    val count = numbers.count { it > 5 }                       // 5
    
    // Finding elements
    val firstEven = numbers.first { it % 2 == 0 }              // 2
    val lastOdd = numbers.last { it % 2 == 1 }                 // 9
    val firstOrNull = numbers.firstOrNull { it > 100 }         // null
    
    // Grouping
    val groupedByLength = names.groupBy { it.length }          // Map<Int, List<String>>
    val grouped = numbers.groupBy { if (it % 2 == 0) "even" else "odd" }
}

// Advanced collection operations
fun advancedOperations() {
    val numbers = (1..10).toList()
    val names = listOf("Alice", "Bob", "Charlie", "Diana", "Eve", "Alice")
    
    // Distinct operations
    val distinctNames = names.distinct()                       // Remove duplicates
    val distinctByLength = names.distinctBy { it.length }      // Distinct by property
    
    // Flattening
    val nestedList = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6))
    val flattened = nestedList.flatten()                       // [1, 2, 3, 4, 5, 6]
    
    // Zipping
    val list1 = listOf("A", "B", "C")
    val list2 = listOf(1, 2, 3)
    val zipped = list1.zip(list2)                              // [("A", 1), ("B", 2), ("C", 3)]
    val zippedWithTransform = list1.zip(list2) { a, b -> "$a$b" } // ["A1", "B2", "C3"]
    
    // Windowing
    val windows = numbers.windowed(3)                          // [[1,2,3], [2,3,4], ...]
    val sliding = numbers.windowed(3, step = 2)                // [[1,2,3], [3,4,5], ...]
    
    // Chunking
    val chunks = numbers.chunked(3)                            // [[1,2,3], [4,5,6], [7,8,9], [10]]
    
    // String operations on collections
    val joined = names.joinToString()                          // "Alice, Bob, Charlie, ..."
    val joinedWithPrefix = names.joinToString(prefix = "[", postfix = "]")
    val joinedWithTransform = names.joinToString { it.uppercase() }
}

// Functional programming with collections
fun functionalProgramming() {
    data class Person(val name: String, val age: Int, val city: String)
    
    val people = listOf(
        Person("Alice", 25, "New York"),
        Person("Bob", 30, "London"),
        Person("Charlie", 22, "New York"),
        Person("Diana", 28, "Paris"),
        Person("Eve", 35, "London")
    )
    
    // Complex data processing pipeline
    val result = people
        .filter { it.age > 25 }                               // People over 25
        .groupBy { it.city }                                  // Group by city
        .mapValues { (city, peopleInCity) ->                  // Transform each group
            peopleInCity
                .sortedByDescending { it.age }                // Sort by age descending
                .map { it.name }                              // Extract names
                .take(2)                                      // Take top 2
        }
        .filter { it.value.size >= 2 }                        // Cities with at least 2 people
    
    println(result)  // {London=[Eve, Bob], New York=[Charlie]}
    
    // Fold and reduce
    val numbers = listOf(1, 2, 3, 4, 5)
    val sum = numbers.reduce { acc, num -> acc + num }        // 15
    val product = numbers.fold(1) { acc, num -> acc * num }   // 120
    
    // Running fold (intermediate results)
    val runningSum = numbers.runningReduce { acc, num -> acc + num } // [1, 3, 6, 10, 15]
    val runningFold = numbers.scan(0) { acc, num -> acc + num }     // [0, 1, 3, 6, 10, 15]
    
    // Lazy sequences for large datasets
    val largeSequence = generateSequence(1) { it + 1 }
        .take(1000000)
        .filter { it % 2 == 0 }
        .map { it * 2 }
        .toList()  // Operations are executed lazily
    
    // Collection transformation to other types
    val nameMap = people.associateBy { it.name }              // Map<String, Person>
    val ageMap = people.associate { it.name to it.age }       // Map<String, Int>
    val cityGroups = people.groupBy { it.city }               // Map<String, List<Person>>
    
    // Set operations
    val set1 = setOf(1, 2, 3, 4)
    val set2 = setOf(3, 4, 5, 6)
    
    val union = set1.union(set2)              // [1, 2, 3, 4, 5, 6]
    val intersect = set1.intersect(set2)      // [3, 4]
    val subtract = set1.subtract(set2)        // [1, 2]
}

Functional Programming Concepts

Kotlin supports functional programming with higher-order functions, lambdas, and function composition.
// Higher-order functions in depth
fun higherOrderFunctions() {
    // Function types
    val stringMapper: (String) -> Int = { it.length }
    val predicate: (Int) -> Boolean = { it > 0 }
    val transformer: (String, Int) -> String = { str, num -> str.repeat(num) }
    
    // Functions returning functions
    fun createMultiplier(factor: Int): (Int) -> Int {
        return { number -> number * factor }
    }
    
    val double = createMultiplier(2)
    val triple = createMultiplier(3)
    
    println(double(5))  // 10
    println(triple(5))  // 15
    
    // Functions taking functions as parameters
    fun <T, R> processItems(
        items: List<T>,
        transform: (T) -> R,
        filter: (T) -> Boolean = { true },
        action: (R) -> Unit
    ) {
        items.filter(filter)
             .map(transform)
             .forEach(action)
    }
    
    val numbers = listOf(1, 2, 3, 4, 5)
    processItems(
        items = numbers,
        transform = { it * it },
        filter = { it % 2 == 0 },
        action = { println("Result: $it") }
    ) // Output: Result: 4, Result: 16
}

// Lambda expressions and closures
fun lambdaExamples() {
    // Basic lambda syntax
    val adder = { x: Int, y: Int -> x + y }
    val greeter = { name: String -> "Hello, $name!" }
    
    // Lambda with receiver
    val stringBuilder: StringBuilder.() -> Unit = {
        append("Hello")
        append(" ")
        append("World")
    }
    
    val result = StringBuilder().apply(stringBuilder).toString()
    println(result)  // Hello World
    
    // Capturing variables (closures)
    var counter = 0
    val incrementer = { 
        counter++ 
        println("Counter: $counter")
    }
    
    incrementer()  // Counter: 1
    incrementer()  // Counter: 2
    
    // Function references
    fun isEven(number: Int) = number % 2 == 0
    fun square(number: Int) = number * number
    
    val numbers = listOf(1, 2, 3, 4, 5)
    val evenSquares = numbers.filter(::isEven)
                             .map(::square)
    
    // Method references
    val strings = listOf("apple", "banana", "cherry")
    val uppercaseStrings = strings.map(String::uppercase)
}

// Function composition and currying
fun advancedFunctional() {
    // Function composition
    fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C = { x -> f(g(x)) }
    
    val length = { s: String -> s.length }
    val isEven = { n: Int -> n % 2 == 0 }
    val isStringLengthEven = compose(isEven, length)
    
    println(isStringLengthEven("Hello"))  // false (length 5)
    println(isStringLengthEven("Hi"))     // true (length 2)
    
    // Currying
    fun <A, B, C> curry(f: (A, B) -> C): (A) -> (B) -> C = { a -> { b -> f(a, b) } }
    
    val add = { a: Int, b: Int -> a + b }
    val curriedAdd = curry(add)
    val add5 = curriedAdd(5)
    
    println(add5(3))  // 8
    println(add5(10)) // 15
    
    // Partial application
    fun multiply(a: Int, b: Int, c: Int) = a * b * c
    val multiplyBy2 = { b: Int, c: Int -> multiply(2, b, c) }
    val multiplyBy2And3 = { c: Int -> multiply(2, 3, c) }
    
    // Memoization for expensive functions
    fun <A, R> memoize(f: (A) -> R): (A) -> R {
        val cache = mutableMapOf<A, R>()
        return { a ->
            cache.getOrPut(a) { f(a) }
        }
    }
    
    val expensiveFunction = { n: Int ->
        println("Computing for $n")
        (1..n).reduce { acc, i -> acc * i }
    }
    
    val memoizedFunction = memoize(expensiveFunction)
    println(memoizedFunction(5))  // Computing for 5, then 120
    println(memoizedFunction(5))  // 120 (from cache)
}

// Functional data structures and patterns
fun functionalPatterns() {
    // Option pattern with nullable types
    fun findUser(id: Int): String? = when (id) {
        1 -> "Alice"
        2 -> "Bob"
        else -> null
    }
    
    fun getEmail(user: String): String? = when (user) {
        "Alice" -> "alice@example.com"
        "Bob" -> "bob@example.com"
        else -> null
    }
    
    // Chaining nullable operations
    val email = findUser(1)?.let { user -> getEmail(user) }
    println(email)  // alice@example.com
    
    // Either pattern with sealed classes
    sealed class Either<out L, out R> {
        data class Left<out L>(val value: L) : Either<L, Nothing>()
        data class Right<out R>(val value: R) : Either<Nothing, R>()
    }
    
    fun parseNumber(s: String): Either<String, Int> = try {
        Either.Right(s.toInt())
    } catch (e: NumberFormatException) {
        Either.Left("Invalid number: $s")
    }
    
    // Using Either
    when (val result = parseNumber("123")) {
        is Either.Right -> println("Parsed number: ${result.value}")
        is Either.Left -> println("Error: ${result.value}")
    }
    
    // Validation with multiple errors
    data class ValidationError(val field: String, val message: String)
    
    fun validateName(name: String): List<ValidationError> = buildList {
        if (name.isBlank()) add(ValidationError("name", "Name cannot be blank"))
        if (name.length < 2) add(ValidationError("name", "Name too short"))
    }
    
    fun validateAge(age: Int): List<ValidationError> = buildList {
        if (age < 0) add(ValidationError("age", "Age cannot be negative"))
        if (age > 150) add(ValidationError("age", "Age seems invalid"))
    }
}

Collection Performance and Best Practices

Understanding collection performance characteristics and choosing the right collection for the job is crucial for writing efficient Kotlin code.
// Performance characteristics
fun collectionPerformance() {
    // List performance
    val list = listOf(1, 2, 3, 4, 5)
    
    // ArrayList - O(1) for get/set, O(n) for add/remove at beginning
    val arrayList = arrayListOf(1, 2, 3, 4, 5)
    arrayList.add(6)           // O(1) amortized
    arrayList.add(0, 0)        // O(n)
    arrayList[2]               // O(1)
    
    // LinkedList - O(n) for get/set, O(1) for add/remove at ends
    val linkedList = LinkedList(list)
    linkedList.addFirst(0)     // O(1)
    linkedList.get(2)          // O(n)
    
    // Set performance
    val hashSet = hashSetOf(1, 2, 3, 4, 5)  // O(1) for contains/add/remove
    val sortedSet = sortedSetOf(1, 2, 3)     // O(log n) for operations
    
    // Map performance
    val hashMap = hashMapOf("a" to 1, "b" to 2)  // O(1) for get/put
    val sortedMap = sortedMapOf("a" to 1, "b" to 2) // O(log n) for operations
    
    // Choosing the right collection
    fun chooseCollection(useCase: String) {
        when (useCase) {
            "frequent access by index" -> ArrayList()
            "frequent add/remove at ends" -> LinkedList()
            "unique elements with fast lookup" -> HashSet()
            "sorted unique elements" -> TreeSet()
            "key-value pairs with fast lookup" -> HashMap()
            "sorted key-value pairs" -> TreeMap()
            else -> List // Default to immutable list
        }
    }
}

// Memory efficiency with sequences
fun sequenceVsCollection() {
    val largeList = (1..1_000_000).toList()
    
    // Eager evaluation with lists (creates intermediate collections)
    val result1 = largeList
        .filter { it % 2 == 0 }      // Creates new list of ~500,000 elements
        .map { it * it }             // Creates another new list
        .take(10)                    // Takes first 10
        .toList()
    
    // Lazy evaluation with sequences (no intermediate collections)
    val result2 = largeList
        .asSequence()                // Convert to sequence
        .filter { it % 2 == 0 }      // Lazy operation
        .map { it * it }             // Lazy operation
        .take(10)                    // Only processes first 10 matching elements
        .toList()                    // Terminal operation
    
    // Sequence generation
    val infiniteSequence = generateSequence(1) { it + 1 }
    val finiteSequence = generateSequence(1) { if (it < 100) it + 1 else null }
    
    val fibonacci = sequence {
        var a = 0
        var b = 1
        while (true) {
            yield(a)
            val next = a + b
            a = b
            b = next
        }
    }
    
    val first10Fibonacci = fibonacci.take(10).toList()
    println(first10Fibonacci)  // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
}

// Collection best practices
fun collectionBestPractices() {
    // Prefer immutable collections
    val immutableList = listOf(1, 2, 3)        // Read-only
    val immutableMap = mapOf("a" to 1, "b" to 2)
    
    // Use mutable collections only when needed
    val mutableList = mutableListOf(1, 2, 3)
    mutableList.add(4)  // Only if you need to modify
    
    // Use collection builders for complex initialization
    val complexList = buildList {
        add("header")
        addAll(listOf("item1", "item2"))
        if (condition) add("conditional")
    }
    
    // Use specific collection types for performance
    val frequentLookupSet = hashSetOf("a", "b", "c")
    val sortedValues = sortedSetOf(3, 1, 2)  // [1, 2, 3]
    
    // Avoid unnecessary collection copies
    val original = listOf(1, 2, 3)
    
    // Good - uses same collection
    val processed = original.map { it * 2 }
    
    // Bad - unnecessary copy
    val unnecessaryCopy = original.toMutableList().also { it.add(4) }
    
    // Use sequences for large datasets or chained operations
    val largeData = (1..1_000_000).toList()
    val optimized = largeData.asSequence()
        .filter { it % 2 == 0 }
        .map { it * it }
        .take(1000)
        .toList()
    
    // Collection utility functions
    val numbers = listOf(1, 2, 3, 4, 5)
    
    // Safe operations
    val firstOrNull = numbers.firstOrNull { it > 10 }  // null instead of exception
    val elementAtOrNull = numbers.elementAtOrNull(10)  // null instead of exception
    
    // Default values
    val firstOrDefault = numbers.firstOrNull() ?: -1
    val maxOrZero = numbers.maxOrNull() ?: 0
    
    // Collection transformations
    val associateBy = numbers.associateBy { "key_$it" }  // Map<String, Int>
    val groupBy = numbers.groupBy { it % 2 }             // Map<Int, List<Int>>
    
    // Collection checks
    val allPositive = numbers.all { it > 0 }             // true
    val anyEven = numbers.any { it % 2 == 0 }            // true
    val noneNegative = numbers.none { it < 0 }           // true
}

4. Coroutines & Asynchronous Programming

Introduction to Coroutines

Coroutines are Kotlin's solution for asynchronous programming. They provide a way to write asynchronous code in a sequential manner, making it easier to read and maintain.
// Basic coroutine setup (requires kotlinx-coroutines-core dependency)
import kotlinx.coroutines.*

fun main() {
    // Launching first coroutine
    println("Main program starts: ${Thread.currentThread().name}")
    
    // GlobalScope (use carefully - coroutine lives as long as the application)
    GlobalScope.launch {
        println("Coroutine starts: ${Thread.currentThread().name}")
        delay(1000)  // Suspends coroutine without blocking the thread
        println("Coroutine ends: ${Thread.currentThread().name}")
    }
    
    // Keep main thread alive to see coroutine output
    Thread.sleep(2000)
    println("Main program ends: ${Thread.currentThread().name}")
}

// Structured concurrency with runBlocking
fun structuredConcurrency() {
    // runBlocking blocks the current thread until all coroutines inside complete
    runBlocking {
        println("Main coroutine starts: ${Thread.currentThread().name}")
        
        // Launch child coroutine
        launch {
            println("Child coroutine starts: ${Thread.currentThread().name}")
            delay(1000)
            println("Child coroutine ends: ${Thread.currentThread().name}")
        }
        
        println("Main coroutine continues: ${Thread.currentThread().name}")
        // runBlocking waits for all launched coroutines to complete
    }
}

// Coroutine builders: launch vs async
fun coroutineBuilders() = runBlocking {
    // launch - fire and forget, returns Job
    val job = launch {
        delay(1000)
        println("World!")
    }
    println("Hello,")
    job.join()  // Wait for the job to complete
    
    // async - returns Deferred<T> (like Future/Promise)
    val deferred: Deferred<Int> = async {
        delay(1000)
        42  // Returns a value
    }
    
    println("Waiting for result...")
    val result = deferred.await()  // Get the result
    println("Result: $result")
    
    // Parallel decomposition
    val time = measureTimeMillis {
        val one = async { doSomethingUsefulOne() }
        val two = async { doSomethingUsefulTwo() }
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

suspend fun doSomethingUsefulOne(): Int {
    delay(1000)
    return 13
}

suspend fun doSomethingUsefulTwo(): Int {
    delay(1000)
    return 29
}

// Coroutine context and dispatchers
fun coroutineContext() = runBlocking {
    // Different dispatchers for different use cases
    
    // Default - CPU-intensive work
    launch(Dispatchers.Default) {
        println("Default: ${Thread.currentThread().name}")
    }
    
    // IO - network or disk operations
    launch(Dispatchers.IO) {
        println("IO: ${Thread.currentThread().name}")
    }
    
    // Main - UI updates (Android)
    // launch(Dispatchers.Main) {
    //     updateUI()
    // }
    
    // Unconfined - not confined to any specific thread
    launch(Dispatchers.Unconfined) {
        println("Unconfined: ${Thread.currentThread().name}")
    }
    
    // Custom thread pool
    val customDispatcher = newSingleThreadContext("MyThread")
    launch(customDispatcher) {
        println("Custom: ${Thread.currentThread().name}")
    }
    customDispatcher.close()
}

Advanced Coroutine Patterns

Coroutines provide powerful patterns for handling complex asynchronous workflows, error handling, and resource management.
// Coroutine scope and structured concurrency
class MyActivity {
    private val scope = CoroutineScope(Dispatchers.Main + Job())
    
    fun doWork() {
        scope.launch {
            try {
                val data = fetchData()
                updateUI(data)
            } catch (e: Exception) {
                showError(e)
            }
        }
    }
    
    fun onDestroy() {
        scope.cancel()  // Cancel all coroutines when activity is destroyed
    }
    
    private suspend fun fetchData(): String {
        return withContext(Dispatchers.IO) {
            // Simulate network call
            delay(1000)
            "Data from server"
        }
    }
    
    private fun updateUI(data: String) {
        println("Updating UI with: $data")
    }
    
    private fun showError(e: Exception) {
        println("Error: ${e.message}")
    }
}

// Error handling in coroutines
fun errorHandling() = runBlocking {
    // Try-catch in coroutine
    val job = launch {
        try {
            riskyOperation()
        } catch (e: Exception) {
            println("Caught exception: ${e.message}")
        }
    }
    job.join()
    
    // Using CoroutineExceptionHandler
    val exceptionHandler = CoroutineExceptionHandler { _, exception ->
        println("CoroutineExceptionHandler caught: ${exception.message}")
    }
    
    val supervisedJob = SupervisorJob()
    val scope = CoroutineScope(Dispatchers.Default + supervisedJob + exceptionHandler)
    
    scope.launch {
        throw RuntimeException("Failed coroutine")
    }
    
    delay(1000)
    scope.cancel()
}

suspend fun riskyOperation() {
    delay(500)
    throw RuntimeException("Something went wrong!")
}

// Coroutine patterns for common use cases
fun commonPatterns() = runBlocking {
    // Timeout handling
    val result = withTimeoutOrNull(1300) {
        repeat(1000) { i ->
            println("I'm sleeping $i ...")
            delay(500)
        }
        "Done"  // This line won't be reached due to timeout
    }
    println("Result: $result")  // null due to timeout
    
    // Retry mechanism
    suspend fun <T> retry(
        times: Int = 3,
        delay: Long = 1000,
        block: suspend () -> T
    ): T {
        repeat(times - 1) { attempt ->
            try {
                return block()
            } catch (e: Exception) {
                println("Attempt $attempt failed: ${e.message}")
                delay(delay * (attempt + 1))  // Exponential backoff
            }
        }
        return block()  // Last attempt
    }
    
    val data = retry(times = 3) {
        // Simulate flaky operation
        if (Math.random() < 0.7) throw RuntimeException("Temporary failure")
        "Success data"
    }
    println("Final result: $data")
    
    // Parallel processing with error handling
    val deferredList = listOf(
        async { processItem(1) },
        async { processItem(2) },
        async { processItem(3) }
    )
    
    val results = deferredList.awaitAll()
    println("All results: $results")
}

suspend fun processItem(item: Int): String {
    delay(1000)
    return "Processed $item"
}

// Flows for reactive streams
fun flowExamples() = runBlocking {
    // Basic flow
    fun simpleFlow() = flow {
        for (i in 1..3) {
            delay(100)
            emit(i)  // Emit value to the flow
        }
    }
    
    // Collect flow values
    simpleFlow().collect { value ->
        println("Received: $value")
    }
    
    // Flow operators
    fun numberFlow() = flow {
        for (i in 1..5) {
            emit(i)
        }
    }
    
    numberFlow()
        .filter { it % 2 == 0 }
        .map { it * it }
        .collect { println("Processed: $it") }
    
    // Exception handling in flows
    fun flowWithError() = flow {
        for (i in 1..3) {
            if (i == 2) throw RuntimeException("Error on $i")
            emit(i)
        }
    }
    
    flowWithError()
        .catch { e -> emit(-1) }  // Handle exception and emit fallback
        .collect { println("Value: $it") }
    
    // StateFlow and SharedFlow for state management
    val stateFlow = MutableStateFlow(0)
    
    // Collect state changes
    val job = launch {
        stateFlow.collect { value ->
            println("State changed to: $value")
        }
    }
    
    stateFlow.value = 1
    stateFlow.value = 2
    
    job.cancel()
}

Channels and Actor Patterns

Channels provide a way for coroutines to communicate with each other, enabling powerful patterns like producer-consumer and actor models.
// Basic channel operations
fun channelBasics() = runBlocking {
    // Create a channel
    val channel = Channel<Int>()
    
    // Producer coroutine
    launch {
        for (x in 1..5) {
            channel.send(x * x)  // Send data to channel
            delay(100)
        }
        channel.close()  // Close channel when done
    }
    
    // Consumer coroutine
    launch {
        for (y in channel) {  // Iterate over channel values
            println("Received: $y")
        }
        println("Channel closed")
    }
}

// Different channel types
fun channelTypes() = runBlocking {
    // Rendezvous channel (default) - no buffer
    val rendezvousChannel = Channel<Int>()
    
    // Buffered channel
    val bufferedChannel = Channel<Int>(10)  // Buffer of 10
    
    // Conflated channel - only keeps the latest value
    val conflatedChannel = Channel<Int>(Channel.CONFLATED)
    
    // Unlimited channel - theoretically unlimited buffer
    val unlimitedChannel = Channel<Int>(Channel.UNLIMITED)
    
    // Producer context
    val producer = launch {
        repeat(5) { i ->
            println("Sending: $i")
            bufferedChannel.send(i)
        }
        bufferedChannel.close()
    }
    
    // Consumer context
    val consumer = launch {
        for (value in bufferedChannel) {
            println("Received: $value")
            delay(200)  // Slower than producer
        }
    }
    
    producer.join()
    consumer.join()
}

// Actor pattern for shared mutable state
fun actorPattern() = runBlocking {
    // Message types for actor
    sealed class CounterMessage {
        object Increment : CounterMessage()
        class GetValue(val response: CompletableDeferred<Int>) : CounterMessage()
    }
    
    // Actor coroutine
    fun CoroutineScope.counterActor() = actor<CounterMessage> {
        var counter = 0
        
        for (msg in channel) {
            when (msg) {
                is CounterMessage.Increment -> counter++
                is CounterMessage.GetValue -> msg.response.complete(counter)
            }
        }
    }
    
    val counter = counterActor()
    
    // Send messages to actor
    val incrementJobs = List(10) {
        launch {
            repeat(1000) {
                counter.send(CounterMessage.Increment)
            }
        }
    }
    
    incrementJobs.forEach { it.join() }
    
    // Get final value
    val response = CompletableDeferred<Int>()
    counter.send(CounterMessage.GetValue(response))
    println("Counter = ${response.await()}")
    counter.close()
}

// Pipeline pattern with channels
fun pipelinePattern() = runBlocking {
    // First stage: generate numbers
    fun CoroutineScope.produceNumbers() = produce<Int> {
        var x = 1
        while (true) {
            send(x++)
            delay(100)
        }
    }
    
    // Second stage: square numbers
    fun CoroutineScope.square(numbers: ReceiveChannel<Int>) = produce<Int> {
        for (x in numbers) {
            send(x * x)
        }
    }
    
    // Third stage: filter even squares
    fun CoroutineScope.filterEven(squares: ReceiveChannel<Int>) = produce<Int> {
        for (x in squares) {
            if (x % 2 == 0) {
                send(x)
            }
        }
    }
    
    val numbers = produceNumbers()
    val squares = square(numbers)
    val evens = filterEven(squares)
    
    // Consume the pipeline
    repeat(5) {
        println(evens.receive())
    }
    
    coroutineContext.cancelChildren()  // Cancel all child coroutines
}

// Fan-out and fan-in patterns
fun fanOutFanIn() = runBlocking {
    // Producer
    fun producer() = produce<Int> {
        var x = 1
        while (true) {
            send(x++)
            delay(100)
        }
    }
    
    // Processor
    suspend fun process(id: Int, channel: ReceiveChannel<Int>) {
        for (msg in channel) {
            println("Processor $id processing $msg")
            delay(200)  // Simulate processing time
        }
    }
    
    val producerChannel = producer()
    
    // Fan-out: multiple consumers from one producer
    repeat(3) { id ->
        launch {
            process(id, producerChannel)
        }
    }
    
    delay(1000)
    producerChannel.cancel()
    
    // Fan-in: multiple producers to one consumer
    suspend fun sendNumbers(channel: SendChannel<Int>, start: Int) {
        var x = start
        while (true) {
            channel.send(x)
            x += 2
            delay(100)
        }
    }
    
    val consumerChannel = Channel<Int>()
    
    // Multiple producers
    repeat(3) { id ->
        launch {
            sendNumbers(consumerChannel, id + 1)
        }
    }
    
    // Single consumer
    launch {
        for (msg in consumerChannel) {
            println("Consumed: $msg")
        }
    }
    
    delay(1000)
    consumerChannel.cancel()
}

Testing Coroutines and Best Practices

Testing coroutines requires special consideration. Kotlin provides tools and patterns for effective coroutine testing and debugging.
// Testing coroutines with TestCoroutineDispatcher
// Add dependency: testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test'

class CoroutineTestExample {
    // @Test
    fun testCoroutine() = runTest {  // runTest from kotlinx-coroutines-test
        val testDispatcher = StandardTestDispatcher()
        
        val viewModel = MyViewModel(testDispatcher)
        
        // Test async operation
        viewModel.loadData()
        
        // Advance time
        advanceTimeBy(1000)
        
        // Verify results
        // assertEquals("Expected data", viewModel.data.value)
    }
}

class MyViewModel(private val dispatcher: CoroutineDispatcher) {
    private val scope = CoroutineScope(dispatcher)
    
    fun loadData() {
        scope.launch {
            // Simulate loading data
            delay(1000)
            // Update state
        }
    }
}

// Best practices for coroutines
fun coroutineBestPractices() {
    // 1. Use structured concurrency
    class ProperScopeUsage {
        private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
        
        fun doWork() {
            // Good: coroutine is properly scoped
            scope.launch {
                val data = withContext(Dispatchers.IO) {
                    fetchData()
                }
                processData(data)
            }
        }
        
        fun cleanup() {
            scope.cancel()
        }
    }
    
    // 2. Handle exceptions properly
    class ExceptionHandling {
        private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
        private val exceptionHandler = CoroutineExceptionHandler { _, e ->
            println("Caught exception: $e")
        }
        
        fun safeOperation() {
            scope.launch(exceptionHandler) {
                try {
                    riskyCall()
                } catch (e: Exception) {
                    // Handle expected exceptions
                    println("Expected exception: $e")
                }
            }
        }
    }
    
    // 3. Choose the right dispatcher
    fun dispatcherSelection() = runBlocking {
        // CPU-bound work
        launch(Dispatchers.Default) {
            heavyComputation()
        }
        
        // IO-bound work
        launch(Dispatchers.IO) {
            networkCall()
        }
        
        // UI updates (Android)
        // launch(Dispatchers.Main) {
        //     updateUI()
        // }
    }
    
    // 4. Use timeouts for network operations
    suspend fun <T> withTimeoutSafe(
        timeout: Long = 5000,
        block: suspend () -> T
    ): Result<T> = try {
        Result.success(withTimeout(timeout) { block() })
    } catch (e: TimeoutCancellationException) {
        Result.failure(e)
    } catch (e: Exception) {
        Result.failure(e)
    }
    
    // 5. Avoid blocking in coroutines
    suspend fun properSuspension() {
        // Good: use delay (suspending)
        delay(1000)
        
        // Bad: don't use Thread.sleep (blocking)
        // Thread.sleep(1000)
    }
    
    // 6. Use flows for streams of data
    fun flowForStreams(): Flow<String> = flow {
        var counter = 0
        while (true) {
            emit("Item $counter")
            delay(1000)
            counter++
        }
    }
    
    // 7. Proper resource cleanup
    class ResourceManagement {
        suspend fun useResource() {
            val resource = acquireResource()
            try {
                // Use resource
                resource.useIt()
            } finally {
                resource.close()
            }
        }
        
        // Or use use extension function
        suspend fun useResourceBetter() {
            acquireResource().use { resource ->
                resource.useIt()
            }
        }
    }
}

// Debugging coroutines
fun debuggingCoroutines() = runBlocking {
    // Enable coroutine debugging
    System.setProperty("kotlinx.coroutines.debug", "on")
    
    // Use coroutine names for debugging
    launch(CoroutineName("NetworkCall")) {
        println("Running in: ${coroutineContext[CoroutineName]}")
        // Network operation
    }
    
    // Log coroutine context
    launch {
        println("Coroutine context: $coroutineContext")
    }
    
    // Use async for parallel operations with proper error handling
    val deferred1 = async(CoroutineName("Operation1")) { operation1() }
    val deferred2 = async(CoroutineName("Operation2")) { operation2() }
    
    try {
        val results = awaitAll(deferred1, deferred2)
        println("Results: $results")
    } catch (e: Exception) {
        println("One of the operations failed: $e")
    }
}

suspend fun operation1(): String {
    delay(500)
    return "Result1"
}

suspend fun operation2(): String {
    delay(700)
    return "Result2"
}

// Mocking coroutines in tests
interface DataRepository {
    suspend fun fetchData(): String
}

class FakeRepository : DataRepository {
    override suspend fun fetchData(): String {
        delay(100)  // Simulate delay
        return "Fake data"
    }
}

class ViewModel(private val repository: DataRepository) {
    private val scope = CoroutineScope(Dispatchers.Main)
    
    fun loadData(callback: (String) -> Unit) {
        scope.launch {
            val data = repository.fetchData()
            callback(data)
        }
    }
}

5. Android Development with Kotlin

Android Fundamentals with Kotlin

Kotlin has become the preferred language for Android development. Here are the fundamental concepts and patterns used in modern Android apps.
// Basic Android Activity with Kotlin
class MainActivity : AppCompatActivity() {
    
    private lateinit var binding: ActivityMainBinding
    private val viewModel: MainViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // View Binding
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        setupUI()
        setupObservers()
    }
    
    private fun setupUI() {
        binding.button.setOnClickListener {
            viewModel.onButtonClicked()
        }
        
        binding.recyclerView.apply {
            layoutManager = LinearLayoutManager(this@MainActivity)
            adapter = MyAdapter()
        }
    }
    
    private fun setupObservers() {
        viewModel.uiState.observe(this) { state ->
            when (state) {
                is UiState.Loading -> showLoading()
                is UiState.Success -> showData(state.data)
                is UiState.Error -> showError(state.message)
            }
        }
        
        viewModel.events.observe(this) { event ->
            when (event) {
                is MainEvent.NavigateToDetails -> navigateToDetails(event.itemId)
            }
        }
    }
    
    private fun showLoading() {
        binding.progressBar.visibility = View.VISIBLE
        binding.content.visibility = View.GONE
    }
    
    private fun showData(data: List<Item>) {
        binding.progressBar.visibility = View.GONE
        binding.content.visibility = View.VISIBLE
        (binding.recyclerView.adapter as MyAdapter).submitList(data)
    }
    
    private fun showError(message: String) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }
    
    private fun navigateToDetails(itemId: String) {
        val intent = Intent(this, DetailActivity::class.java).apply {
            putExtra("ITEM_ID", itemId)
        }
        startActivity(intent)
    }
}

// ViewModel with Kotlin
class MainViewModel : ViewModel() {
    
    private val repository = DataRepository()
    
    private val _uiState = MutableStateFlow<UiState<List<Item>>>(UiState.Loading)
    val uiState: StateFlow<UiState<List<Item>>> = _uiState.asStateFlow()
    
    private val _events = MutableSharedFlow<MainEvent>()
    val events: SharedFlow<MainEvent> = _events.asSharedFlow()
    
    init {
        loadData()
    }
    
    fun onButtonClicked() {
        viewModelScope.launch {
            _events.emit(MainEvent.NavigateToDetails("123"))
        }
    }
    
    private fun loadData() {
        viewModelScope.launch {
            _uiState.value = UiState.Loading
            try {
                val data = repository.getItems()
                _uiState.value = UiState.Success(data)
            } catch (e: Exception) {
                _uiState.value = UiState.Error(e.message ?: "Unknown error")
            }
        }
    }
}

// Sealed classes for state and events
sealed class UiState<out T> {
    object Loading : UiState<Nothing>()
    data class Success<T>(val data: T) : UiState<T>()
    data class Error(val message: String) : UiState<Nothing>()
}

sealed class MainEvent {
    data class NavigateToDetails(val itemId: String) : MainEvent()
}

// RecyclerView Adapter with Kotlin
class MyAdapter : ListAdapter<Item, MyAdapter.ViewHolder>(DiffCallback) {
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemLayoutBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
        return ViewHolder(binding)
    }
    
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = getItem(position)
        holder.bind(item)
    }
    
    inner class ViewHolder(
        private val binding: ItemLayoutBinding
    ) : RecyclerView.ViewHolder(binding.root) {
        
        fun bind(item: Item) {
            binding.title.text = item.title
            binding.description.text = item.description
            binding.root.setOnClickListener {
                // Handle click
            }
        }
    }
    
    companion object {
        private val DiffCallback = object : DiffUtil.ItemCallback<Item>() {
            override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
                return oldItem.id == newItem.id
            }
            
            override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
                return oldItem == newItem
            }
        }
    }
}

// Data classes for models
data class Item(
    val id: String,
    val title: String,
    val description: String,
    val imageUrl: String,
    val createdAt: Date
)

Jetpack Compose - Modern UI Toolkit

Jetpack Compose is Android's modern toolkit for building native UI. It simplifies and accelerates UI development with Kotlin.
// Basic Composable function
@Composable
fun Greeting(name: String) {
    Text(
        text = "Hello $name!",
        style = MaterialTheme.typography.h4,
        color = MaterialTheme.colors.primary
    )
}

// Composable with state
@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }
    
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(
            text = "Count: $count",
            style = MaterialTheme.typography.h3
        )
        
        Spacer(modifier = Modifier.height(16.dp))
        
        Row {
            Button(
                onClick = { count++ },
                modifier = Modifier.padding(8.dp)
            ) {
                Text("Increment")
            }
            
            Button(
                onClick = { count-- },
                modifier = Modifier.padding(8.dp)
            ) {
                Text("Decrement")
            }
            
            Button(
                onClick = { count = 0 },
                modifier = Modifier.padding(8.dp)
            ) {
                Text("Reset")
            }
        }
    }
}

// List composable with LazyColumn
@Composable
fun ItemList(items: List<Item>) {
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        contentPadding = PaddingValues(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(items) { item ->
            ItemCard(item = item)
        }
    }
}

@Composable
fun ItemCard(item: Item) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .clickable { /* Handle click */ },
        elevation = 4.dp,
        shape = MaterialTheme.shapes.medium
    ) {
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            Text(
                text = item.title,
                style = MaterialTheme.typography.h6,
                color = MaterialTheme.colors.onSurface
            )
            
            Spacer(modifier = Modifier.height(4.dp))
            
            Text(
                text = item.description,
                style = MaterialTheme.typography.body2,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f)
            )
            
            Spacer(modifier = Modifier.height(8.dp))
            
            Row(
                verticalAlignment = Alignment.CenterVertically
            ) {
                Icon(
                    imageVector = Icons.Default.Favorite,
                    contentDescription = "Favorite",
                    tint = MaterialTheme.colors.primary,
                    modifier = Modifier.size(16.dp)
                )
                
                Spacer(modifier = Modifier.width(4.dp))
                
                Text(
                    text = "Like",
                    style = MaterialTheme.typography.caption,
                    color = MaterialTheme.colors.primary
                )
            }
        }
    }
}

// ViewModel integration with Compose
@Composable
fun MainScreen(
    viewModel: MainViewModel = hiltViewModel()
) {
    val uiState by viewModel.uiState.collectAsState()
    
    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text("My App") },
                actions = {
                    IconButton(onClick = { viewModel.onSettingsClicked() }) {
                        Icon(Icons.Default.Settings, contentDescription = "Settings")
                    }
                }
            )
        },
        floatingActionButton = {
            FloatingActionButton(onClick = { viewModel.onFabClicked() }) {
                Icon(Icons.Default.Add, contentDescription = "Add")
            }
        }
    ) { paddingValues ->
        when (val state = uiState) {
            is UiState.Loading -> LoadingScreen()
            is UiState.Success -> ItemList(
                items = state.data,
                modifier = Modifier.padding(paddingValues)
            )
            is UiState.Error -> ErrorScreen(
                message = state.message,
                onRetry = { viewModel.loadData() },
                modifier = Modifier.padding(paddingValues)
            )
        }
    }
}

@Composable
fun LoadingScreen() {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        CircularProgressIndicator()
    }
}

@Composable
fun ErrorScreen(
    message: String,
    onRetry: () -> Unit,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Icon(
            imageVector = Icons.Default.Error,
            contentDescription = "Error",
            tint = MaterialTheme.colors.error,
            modifier = Modifier.size(64.dp)
        )
        
        Spacer(modifier = Modifier.height(16.dp))
        
        Text(
            text = message,
            style = MaterialTheme.typography.body1,
            textAlign = TextAlign.Center
        )
        
        Spacer(modifier = Modifier.height(16.dp))
        
        Button(onClick = onRetry) {
            Text("Retry")
        }
    }
}

// Navigation with Compose
@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    
    NavHost(
        navController = navController,
        startDestination = "main"
    ) {
        composable("main") {
            MainScreen { itemId ->
                navController.navigate("details/$itemId")
            }
        }
        
        composable(
            "details/{itemId}",
            arguments = listOf(navArgument("itemId") { type = NavType.StringType })
        ) { backStackEntry ->
            val itemId = backStackEntry.arguments?.getString("itemId") ?: ""
            DetailScreen(itemId = itemId) {
                navController.popBackStack()
            }
        }
    }
}

// Theme customization
@Composable
fun MyAppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colors = if (darkTheme) {
        DarkColorPalette
    } else {
        LightColorPalette
    }
    
    MaterialTheme(
        colors = colors,
        typography = MyTypography,
        shapes = MyShapes,
        content = content
    )
}

Dependency Injection with Hilt

Hilt is a dependency injection library for Android that reduces boilerplate code and makes DI easier to implement.
// Application setup
@HiltAndroidApp
class MyApplication : Application()

// Module definitions
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    
    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    
    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
    
    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext context: Context): AppDatabase {
        return Room.databaseBuilder(
            context,
            AppDatabase::class.java,
            "app-database"
        ).build()
    }
}

@Module
@InstallIn(ViewModelComponent::class)
object ViewModelModule {
    
    @Provides
    fun provideRepository(
        apiService: ApiService,
        database: AppDatabase
    ): DataRepository {
        return DataRepositoryImpl(apiService, database)
    }
}

// Repository implementation
class DataRepositoryImpl @Inject constructor(
    private val apiService: ApiService,
    private val database: AppDatabase
) : DataRepository {
    
    override suspend fun getItems(): List<Item> {
        return try {
            // Try to get from network first
            val networkItems = apiService.getItems()
            
            // Cache to database
            database.itemDao().insertAll(networkItems)
            
            networkItems
        } catch (e: Exception) {
            // Fall back to local database
            database.itemDao().getAll()
        }
    }
}

// Hilt ViewModel
@HiltViewModel
class MainViewModel @Inject constructor(
    private val repository: DataRepository
) : ViewModel() {
    
    private val _uiState = MutableStateFlow<UiState<List<Item>>>(UiState.Loading)
    val uiState: StateFlow<UiState<List<Item>>> = _uiState.asStateFlow()
    
    init {
        loadData()
    }
    
    fun loadData() {
        viewModelScope.launch {
            _uiState.value = UiState.Loading
            try {
                val items = repository.getItems()
                _uiState.value = UiState.Success(items)
            } catch (e: Exception) {
                _uiState.value = UiState.Error(e.message ?: "Unknown error")
            }
        }
    }
}

// Hilt in Activities and Fragments
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    
    // Injected by Hilt
    @Inject
    lateinit var analytics: AnalyticsService
    
    private val viewModel: MainViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
    }
}

// Custom scopes and qualifiers
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptorOkHttpClient

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    
    @AuthInterceptorOkHttpClient
    @Provides
    @Singleton
    fun provideAuthOkHttpClient(authInterceptor: AuthInterceptor): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(authInterceptor)
            .build()
    }
    
    @OtherInterceptorOkHttpClient
    @Provides
    @Singleton
    fun provideOtherOkHttpClient(otherInterceptor: OtherInterceptor): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(otherInterceptor)
            .build()
    }
    
    @Provides
    @Singleton
    fun provideAuthRetrofit(
        @AuthInterceptorOkHttpClient client: OkHttpClient
    ): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://auth.api.example.com/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}

// Testing with Hilt
@HiltAndroidTest
class MainActivityTest {
    
    @get:Rule
    var hiltRule = HiltAndroidRule(this)
    
    @Inject
    lateinit var repository: DataRepository
    
    @Before
    fun init() {
        hiltRule.inject()
    }
    
    @Test
    fun testActivity() {
        // Test with injected dependencies
    }
}

Advanced Android Patterns

Modern Android development uses advanced patterns like Repository, Use Cases, and Clean Architecture for maintainable and testable code.
// Clean Architecture layers

// Domain layer (business logic)
data class User(
    val id: String,
    val name: String,
    val email: String
)

interface UserRepository {
    suspend fun getUser(id: String): User?
    suspend fun saveUser(user: User)
}

class GetUserUseCase(
    private val userRepository: UserRepository
) {
    suspend operator fun invoke(id: String): User? {
        return userRepository.getUser(id)
    }
}

class SaveUserUseCase(
    private val userRepository: UserRepository
) {
    suspend operator fun invoke(user: User) {
        userRepository.saveUser(user)
    }
}

// Data layer (data sources)
class UserRepositoryImpl(
    private val localDataSource: UserLocalDataSource,
    private val remoteDataSource: UserRemoteDataSource
) : UserRepository {
    
    override suspend fun getUser(id: String): User? {
        return try {
            // Try remote first
            val remoteUser = remoteDataSource.getUser(id)
            remoteUser?.let { localDataSource.saveUser(it) }
            remoteUser
        } catch (e: Exception) {
            // Fall back to local
            localDataSource.getUser(id)
        }
    }
    
    override suspend fun saveUser(user: User) {
        localDataSource.saveUser(user)
        // Optionally sync with remote
    }
}

interface UserLocalDataSource {
    suspend fun getUser(id: String): User?
    suspend fun saveUser(user: User)
}

interface UserRemoteDataSource {
    suspend fun getUser(id: String): User?
}

// Room Database implementation
@Entity(tableName = "users")
data class UserEntity(
    @PrimaryKey
    val id: String,
    val name: String,
    val email: String
)

@Dao
interface UserDao {
    @Query("SELECT * FROM users WHERE id = :id")
    suspend fun getUser(id: String): UserEntity?
    
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun saveUser(user: UserEntity)
    
    @Query("DELETE FROM users")
    suspend fun clearAll()
}

// Retrofit API implementation
interface UserApiService {
    @GET("users/{id}")
    suspend fun getUser(@Path("id") id: String): UserResponse?
}

data class UserResponse(
    val id: String,
    val name: String,
    val email: String
) {
    fun toDomain(): User = User(id, name, email)
    fun toEntity(): UserEntity = UserEntity(id, name, email)
}

// WorkManager for background tasks
class SyncWorker(
    context: Context,
    params: WorkerParameters,
    private val userRepository: UserRepository
) : CoroutineWorker(context, params) {
    
    override suspend fun doWork(): Result {
        return try {
            // Perform sync operation
            syncData()
            Result.success()
        } catch (e: Exception) {
            if (runAttemptCount < 3) {
                Result.retry()
            } else {
                Result.failure()
            }
        }
    }
    
    private suspend fun syncData() {
        // Implementation
    }
}

// Push notifications with FCM
class MyFirebaseMessagingService : FirebaseMessagingService() {
    
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        
        remoteMessage.notification?.let { notification ->
            showNotification(
                title = notification.title ?: "",
                body = notification.body ?: ""
            )
        }
    }
    
    private fun showNotification(title: String, body: String) {
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "default",
                "Default Channel",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)
        }
        
        val notification = NotificationCompat.Builder(this, "default")
            .setContentTitle(title)
            .setContentText(body)
            .setSmallIcon(R.drawable.ic_notification)
            .setAutoCancel(true)
            .build()
        
        notificationManager.notify(1, notification)
    }
}

// Security best practices
class SecurePreferences(context: Context) {
    private val sharedPreferences = context.getSharedPreferences("secure_prefs", Context.MODE_PRIVATE)
    
    fun saveEncryptedValue(key: String, value: String) {
        val encryptedValue = encrypt(value)
        sharedPreferences.edit().putString(key, encryptedValue).apply()
    }
    
    fun getEncryptedValue(key: String): String? {
        val encryptedValue = sharedPreferences.getString(key, null)
        return encryptedValue?.let { decrypt(it) }
    }
    
    private fun encrypt(value: String): String {
        // Implementation using Android Keystore
        return value  // Simplified
    }
    
    private fun decrypt(encryptedValue: String): String {
        // Implementation
        return encryptedValue  // Simplified
    }
}

// Performance optimization
class ImageLoader(private val context: Context) {
    private val memoryCache = LruCache<String, Bitmap>(calculateMemoryCacheSize())
    
    suspend fun loadImage(url: String): Bitmap? = withContext(Dispatchers.IO) {
        // Check memory cache first
        memoryCache[url]?.let { return@withContext it }
        
        // Check disk cache
        val diskCache = getFromDiskCache(url)
        diskCache?.let {
            memoryCache.put(url, it)
            return@withContext it
        }
        
        // Load from network
        val networkBitmap = loadFromNetwork(url)
        networkBitmap?.let {
            saveToDiskCache(url, it)
            memoryCache.put(url, it)
        }
        networkBitmap
    }
    
    private fun calculateMemoryCacheSize(): Int {
        val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
        return maxMemory / 8  // Use 1/8th of available memory
    }
}

6. Advanced Kotlin Features

DSLs (Domain Specific Languages)

Kotlin's powerful features enable creating internal DSLs that provide fluent, readable APIs for specific domains.
// HTML Builder DSL
fun html(block: HTML.() -> Unit): HTML {
    return HTML().apply(block)
}

class HTML {
    private val children = mutableListOf<Element>()
    
    fun head(block: Head.() -> Unit) {
        children.add(Head().apply(block))
    }
    
    fun body(block: Body.() -> Unit) {
        children.add(Body().apply(block))
    }
    
    override fun toString(): String {
        return """<!DOCTYPE html>
<html>
${children.joinToString("\n")}
</html>"""
    }
}

class Head {
    private val children = mutableListOf<Element>()
    
    fun title(text: String) {
        children.add(Tag("title", text))
    }
    
    fun script(src: String) {
        children.add(EmptyTag("script", mapOf("src" to src)))
    }
    
    override fun toString(): String {
        return """<head>
${children.joinToString("\n") { "    $it" }}
</head>"""
    }
}

class Body {
    private val children = mutableListOf<Element>()
    
    fun h1(text: String) {
        children.add(Tag("h1", text))
    }
    
    fun p(block: P.() -> Unit) {
        children.add(P().apply(block))
    }
    
    fun div(block: Div.() -> Unit) {
        children.add(Div().apply(block))
    }
    
    override fun toString(): String {
        return """<body>
${children.joinToString("\n") { "    $it" }}
</body>"""
    }
}

class P {
    private var text = ""
    
    operator fun String.unaryPlus() {
        text += this
    }
    
    override fun toString() = """<p>$text</p>"""
}

class Div {
    private val children = mutableListOf<Element>()
    private val attributes = mutableMapOf<String, String>()
    
    fun id(value: String) {
        attributes["id"] = value
    }
    
    fun className(value: String) {
        attributes["class"] = value
    }
    
    fun p(block: P.() -> Unit) {
        children.add(P().apply(block))
    }
    
    override fun toString(): String {
        val attrs = attributes.entries.joinToString(" ") { """${it.key}="${it.value}"""" }
        return """<div$attrs>
${children.joinToString("\n") { "    $it" }}
</div>"""
    }
}

sealed class Element
class Tag(val name: String, val content: String) : Element() {
    override fun toString() = """<$name>$content</$name>"""
}
class EmptyTag(val name: String, val attributes: Map<String, String> = emptyMap()) : Element() {
    override fun toString(): String {
        val attrs = attributes.entries.joinToString(" ") { """${it.key}="${it.value}"""" }
        return """<$name$attrs />"""
    }
}

// Usage of HTML DSL
fun createHTMLPage() = html {
    head {
        title("My Page")
        script("app.js")
    }
    body {
        h1("Welcome to Kotlin DSL")
        div {
            id("content")
            className("container")
            p {
                +"This is a paragraph created with "
                +"Kotlin DSL"
            }
        }
    }
}

// Gradle Kotlin DSL style
class Dependencies {
    private val implementations = mutableListOf<String>()
    private val testImplementations = mutableListOf<String>()
    
    fun implementation(dependency: String) {
        implementations.add(dependency)
    }
    
    fun testImplementation(dependency: String) {
        testImplementations.add(dependency)
    }
    
    override fun toString(): String {
        return """dependencies {
    ${implementations.joinToString("\n    ") { "implementation(""""$it"""")" }}
    ${testImplementations.joinToString("\n    ") { "testImplementation(""""$it"""")" }}
}"""
    }
}

fun dependencies(block: Dependencies.() -> Unit): String {
    return Dependencies().apply(block).toString()
}

// Usage
val deps = dependencies {
    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.0")
    implementation("androidx.core:core-ktx:1.12.0")
    testImplementation("junit:junit:4.13.2")
}

Metaprogramming with Annotations and Reflection

Kotlin provides metaprogramming capabilities through annotations and reflection for building frameworks and code generation tools.
// Custom annotations
@Target(AnnotationTarget.CLASS)
annotation class Entity(val tableName: String)

@Target(AnnotationTarget.PROPERTY)
annotation class Column(val name: String)

@Target(AnnotationTarget.PROPERTY)
annotation class Id

@Target(AnnotationTarget.FUNCTION)
annotation class Test(val priority: Int = 1)

// Using annotations
@Entity(tableName = "users")
data class User(
    @Id
    val id: Long,
    
    @Column(name = "user_name")
    val name: String,
    
    @Column(name = "email_address")
    val email: String,
    
    val age: Int  // No annotation - uses property name
)

class TestSuite {
    @Test(priority = 1)
    fun testBasicFunctionality() {
        // Test implementation
    }
    
    @Test(priority = 2)
    fun testAdvancedFeatures() {
        // Test implementation
    }
}

// Reflection examples
fun reflectionExamples() {
    val user = User(1, "John Doe", "john@example.com", 30)
    
    // Class reference
    val kClass = user::class
    println("Class name: ${kClass.simpleName}")
    println("Properties:")
    
    // Iterate through properties
    kClass.memberProperties.forEach { property ->
        println("  ${property.name} = ${property.get(user)}")
    }
    
    // Find annotations
    kClass.annotations.forEach { annotation ->
        when (annotation) {
            is Entity -> println("Table name: ${annotation.tableName}")
        }
    }
    
    // Call function by name
    val method = kClass.members.find { it.name == "toString" }
    val result = method?.call(user)
    println("toString result: $result")
}

// Annotation processing with kapt (Kotlin Annotation Processing Tool)
// Note: This would typically be in a separate processor module

// Simple ORM using reflection
class SimpleORM {
    fun <T : Any> createTable(entity: T): String {
        val kClass = entity::class
        val tableName = getTableName(kClass)
        val columns = getColumns(kClass)
        
        return """CREATE TABLE $tableName (
    ${columns.joinToString(",\n    ")}
);"""
    }
    
    fun <T : Any> insert(entity: T): String {
        val kClass = entity::class
        val tableName = getTableName(kClass)
        val columns = getColumnNames(kClass)
        val values = getColumnValues(kClass, entity)
        
        return """INSERT INTO $tableName (${columns.joinToString()}) 
VALUES (${values.joinToString()});"""
    }
    
    private fun <T : Any> getTableName(kClass: KClass<T>): String {
        return kClass.annotations
            .filterIsInstance<Entity>()
            .firstOrNull()
            ?.tableName
            ?: kClass.simpleName!!.lowercase()
    }
    
    private fun <T : Any> getColumns(kClass: KClass<T>): List<String> {
        return kClass.memberProperties.map { property ->
            val columnName = property.annotations
                .filterIsInstance<Column>()
                .firstOrNull()
                ?.name
                ?: property.name
            
            val type = when (property.returnType.classifier) {
                Long::class -> "BIGINT"
                String::class -> "VARCHAR(255)"
                Int::class -> "INT"
                else -> "TEXT"
            }
            
            val constraints = if (property.annotations.any { it is Id }) {
                " PRIMARY KEY"
            } else {
                ""
            }
            
            """$columnName $type$constraints"""
        }
    }
    
    private fun <T : Any> getColumnNames(kClass: KClass<T>): List<String> {
        return kClass.memberProperties.map { property ->
            property.annotations
                .filterIsInstance<Column>()
                .firstOrNull()
                ?.name
                ?: property.name
        }
    }
    
    private fun <T : Any> getColumnValues(kClass: KClass<T>, entity: T): List<String> {
        return kClass.memberProperties.map { property ->
            val value = property.get(entity)
            when (value) {
                is String -> """'$value'"""
                else -> value.toString()
            }
        }
    }
}

// Usage of SimpleORM
fun useSimpleORM() {
    val user = User(1, "John Doe", "john@example.com", 30)
    val orm = SimpleORM()
    
    println(orm.createTable(user))
    println(orm.insert(user))
}

Kotlin Multiplatform (KMP)

Kotlin Multiplatform allows sharing code between different platforms while keeping platform-specific implementations.
// Shared common module
// In commonMain source set

expect class Platform() {
    val platform: String
}

class Greeting {
    private val platform: Platform = Platform()
    
    fun greet(): String {
        return "Hello, ${platform.platform}!"
    }
}

// Platform-specific implementations
// In androidMain source set
actual class Platform actual constructor() {
    actual val platform: String = "Android"
}

// In iosMain source set
actual class Platform actual constructor() {
    actual val platform: String = "iOS"
}

// In jsMain source set  
actual class Platform actual constructor() {
    actual val platform: String = "JavaScript"
}

// Shared business logic
expect suspend fun readFile(path: String): String?

expect suspend fun writeFile(path: String, content: String)

class FileManager {
    suspend fun processFile(inputPath: String, outputPath: String) {
        val content = readFile(inputPath) ?: return
        val processed = processContent(content)
        writeFile(outputPath, processed)
    }
    
    private fun processContent(content: String): String {
        // Shared processing logic
        return content.uppercase()
    }
}

// Shared networking with Ktor
expect fun httpClient(config: HttpClientConfig<*>.() -> Unit): HttpClient

class ApiClient(private val baseUrl: String) {
    private val client = httpClient {
        install(JsonFeature) {
            serializer = KotlinxSerializer()
        }
    }
    
    suspend fun fetchData(): Data {
        return client.get<Data>("$baseUrl/data")
    }
    
    suspend fun postData(data: Data) {
        client.post<Unit>("$baseUrl/data") {
            body = data
        }
    }
}

// Shared data models
@Serializable
data class Data(
    val id: String,
    val title: String,
    val content: String,
    val timestamp: Long
)

// Shared repository pattern
interface DataRepository {
    suspend fun getData(): List<Data>
    suspend fun saveData(data: Data)
    suspend fun deleteData(id: String)
}

class DataRepositoryImpl(
    private val apiClient: ApiClient,
    private val localDataSource: LocalDataSource
) : DataRepository {
    
    override suspend fun getData(): List<Data> {
        return try {
            // Try to fetch from network
            val remoteData = apiClient.fetchData()
            localDataSource.saveAll(remoteData)
            remoteData
        } catch (e: Exception) {
            // Fall back to local data
            localDataSource.getAll()
        }
    }
    
    override suspend fun saveData(data: Data) {
        localDataSource.save(data)
        // Optionally sync with backend
        try {
            apiClient.postData(data)
        } catch (e: Exception) {
            // Handle sync error
            println("Sync failed: ${e.message}")
        }
    }
    
    override suspend fun deleteData(id: String) {
        localDataSource.delete(id)
    }
}

// Expect/actual for dependency injection
expect class PlatformDependencies {
    val logger: Logger
    val fileSystem: FileSystem
}

// Android implementation
actual class PlatformDependencies actual constructor() {
    actual val logger: Logger = AndroidLogger()
    actual val fileSystem: FileSystem = AndroidFileSystem()
}

// iOS implementation
actual class PlatformDependencies actual constructor() {
    actual val logger: Logger = IOSLogger()
    actual val fileSystem: FileSystem = IOSFileSystem()
}

// Building a multiplatform library
class MyMultiplatformLibrary(
    private val dependencies: PlatformDependencies
) {
    fun doSomething() {
        dependencies.logger.info("Doing something...")
        // Cross-platform logic
    }
}

// Testing in multiplatform
class CommonTest {
    @Test
    fun testCommonLogic() {
        val library = MyMultiplatformLibrary(FakeDependencies())
        // Test common logic
    }
}

class FakeDependencies : PlatformDependencies() {
    override val logger: Logger = FakeLogger()
    override val fileSystem: FileSystem = FakeFileSystem()
}

Performance Optimization and Best Practices

Writing high-performance Kotlin code requires understanding the language's performance characteristics and following best practices.
// Performance optimization techniques

// 1. Use inline functions for higher-order functions
inline fun <T> measureTime(block: () -> T): Pair<T, Long> {
    val start = System.nanoTime()
    val result = block()
    val end = System.nanoTime()
    return result to (end - start)
}

// 2. Use sequences for large collections
fun processLargeDataset() {
    val largeList = (1..1_000_000).toList()
    
    // Bad: creates intermediate collections
    val result1 = largeList
        .filter { it % 2 == 0 }      // Creates 500,000 element list
        .map { it * it }             // Creates another 500,000 element list
        .take(1000)                  // Takes first 1000
        .toList()
    
    // Good: uses sequences (lazy evaluation)
    val result2 = largeList
        .asSequence()                // Convert to sequence
        .filter { it % 2 == 0 }      // Lazy operation
        .map { it * it }             // Lazy operation
        .take(1000)                  // Only processes needed elements
        .toList()                    // Terminal operation
}

// 3. Avoid unnecessary object creation
class Point(val x: Int, val y: Int) {
    // Companion object with cached instances for common values
    companion object {
        val ORIGIN = Point(0, 0)
        val UNIT_X = Point(1, 0)
        val UNIT_Y = Point(0, 1)
    }
}

// 4. Use value classes for wrapper types
@JvmInline
value class UserId(val value: Long)

@JvmInline
value class Email(val value: String)

// These have no runtime overhead compared to using primitives directly

// 5. Optimize string operations
fun stringOptimization() {
    // Bad: creates intermediate strings
    var result = ""
    for (i in 1..1000) {
        result += i  // Creates new string each time
    }
    
    // Good: use StringBuilder
    val builder = StringBuilder()
    for (i in 1..1000) {
        builder.append(i)
    }
    val optimizedResult = builder.toString()
    
    // Even better: use buildString
    val bestResult = buildString {
        for (i in 1..1000) {
            append(i)
        }
    }
}

// 6. Memory-efficient data structures
fun memoryEfficientCollections() {
    // Use primitive arrays when possible
    val intArray = IntArray(1000)  // Uses primitive ints
    val integerList = List(1000) { it }  // Uses boxed Integers
    
    // Use appropriate collection types
    val frequentLookup = hashSetOf(1, 2, 3)  // O(1) lookup
    val sortedValues = sortedSetOf(3, 1, 2)  // O(log n) lookup but sorted
    
    // Use lazy initialization
    val heavyObject by lazy {
        HeavyObject()  // Only created when first accessed
    }
}

// 7. Coroutine performance
suspend fun coroutinePerformance() {
    // Use appropriate dispatchers
    withContext(Dispatchers.Default) {
        // CPU-intensive work
        heavyComputation()
    }
    
    withContext(Dispatchers.IO) {
        // IO-bound work
        readLargeFile()
    }
    
    // Use channels for communication between coroutines
    val channel = Channel<Data>()
    
    // Producer
    launch {
        for (i in 1..1000) {
            channel.send(Data(i))
        }
        channel.close()
    }
    
    // Consumer
    launch {
        for (data in channel) {
            process(data)
        }
    }
}

// 8. Cache expensive computations
class ExpensiveComputation {
    private val cache = mutableMapOf<Int, String>()
    
    fun compute(input: Int): String {
        return cache.getOrPut(input) {
            // Expensive computation
            Thread.sleep(100)
            "result_$input"
        }
    }
}

// 9. Avoid boxing in performance-critical code
fun avoidBoxing() {
    // Primitive arrays
    val primitiveArray = intArrayOf(1, 2, 3)  // No boxing
    val boxedArray = arrayOf(1, 2, 3)         // Boxed Integers
    
    // Use value classes
    data class Boxed(val value: Int)           // Regular class
    @JvmInline value class Inline(val value: Int) // No runtime overhead
}

// 10. Profile and measure
fun profilingExample() {
    // Use measureTimeMillis for quick measurements
    val time = measureTimeMillis {
        expensiveOperation()
    }
    println("Operation took ${time}ms")
    
    // Use profiling tools for detailed analysis
    // - Android Profiler
    // - YourKit
    // - Java Mission Control
}

// Best practices for production code

// 1. Use sealed classes for state management
sealed class NetworkResult<out T> {
    object Loading : NetworkResult<Nothing>()
    data class Success<T>(val data: T) : NetworkResult<T>()
    data class Error(val message: String, val code: Int) : NetworkResult<Nothing>()
}

// 2. Prefer immutability
data class User(
    val id: String,        // Immutable
    val name: String,      // Immutable
    val email: String      // Immutable
) {
    // Provide copy methods for "modifications"
    fun withName(newName: String) = copy(name = newName)
    fun withEmail(newEmail: String) = copy(email = newEmail)
}

// 3. Use extension functions wisely
fun String.isValidEmail(): Boolean {
    return contains("@") && length > 5
}

fun List<String>.filterValidEmails(): List<String> {
    return filter { it.isValidEmail() }
}

// 4. Proper error handling
suspend fun <T> safeApiCall(block: suspend () -> T): Result<T> {
    return try {
        Result.success(block())
    } catch (e: Exception) {
        Result.failure(e)
    }
}

// 5. Resource management
fun readFileSafely(path: String): String? {
    return File(path).takeIf { it.exists() }?.use { file ->
        file.readText()
    }
}

💻 Kotlin Practice Projects

Beginner Level

  • 1Build a Command Line Calculator with basic operations
  • 2Create a Todo List Application with file persistence
  • 3Implement a Number Guessing Game with user input
  • 4Build a Simple Bank Account Management System
  • 5Create a Temperature Converter between Celsius/Fahrenheit

Intermediate Level

  • 1Develop a REST API Client with error handling
  • 2Build a Chat Application with WebSocket connections
  • 3Create a Budget Tracker with data visualization
  • 4Implement a Weather App with API integration
  • 5Build a Note-taking App with search and categories

Advanced Level

  • 1Create a Multiplatform Mobile App with KMP
  • 2Build a Microservices Architecture with Ktor
  • 3Develop a Custom DSL for configuration files
  • 4Implement a Caching System with expiration
  • 5Build a Real-time Dashboard with coroutines and flows

📋 Kotlin Quick Reference

Core Concepts

  • val/var - Immutable/mutable variables
  • fun - Function declaration
  • class/data class - Class definitions
  • null safety - ?. ?: !! operators
  • Extension functions - Adding methods to existing classes
  • Lambda expressions - { param -> body }
  • Coroutines - Async programming

Common Patterns

  • Sealed classes - Restricted hierarchies
  • Builder pattern - DSL creation
  • Repository pattern - Data abstraction
  • Dependency Injection - Hilt/Koin
  • MVVM Architecture - ViewModel + LiveData
  • Functional programming - map/filter/reduce
  • Error handling - Result/Try-catch

Master the Language That's Revolutionizing Development!

Kotlin has transformed modern software development with its concise syntax, powerful features, and excellent tooling support. From Android apps to backend services and cross-platform solutions, Kotlin provides a unified development experience that boosts productivity and code quality.

Understanding Kotlin opens doors to Android development, server-side programming, and multiplatform projects. Its interoperability with Java, null safety features, and coroutine support make it an ideal choice for building robust, maintainable applications across all platforms.

Happy Kotlin Coding! 🚀

This comprehensive guide covers Kotlin from basic syntax to advanced patterns like coroutines, multiplatform development, and Android integration.

Essential for Android development, backend services, and modern software engineering.

© 2025 Kotlin Mastery Guide | Write Better Code, Faster