Kotlin Introduction

Kotlin is a modern, concise, and type-safe programming language developed by JetBrains. It's the preferred language for Android development and is fully interoperable with Java.

Why Kotlin?

  • Concise — 40% fewer lines of code than Java
  • Null safe — Eliminates NullPointerException at compile time
  • Coroutines — Built-in async/await support
  • Interoperable — 100% compatible with Java libraries
  • Android official — Google's recommended language since 2019
  • Multiplatform — Shared code across Android, iOS, web, desktop

Hello World

Kotlin
fun main() {
    println("Hello, World!")
    
    // Variables
    val name = "Alice"         // Immutable (val)
    var age = 28               // Mutable (var)
    
    // String interpolation
    println("Name: $name, Age: $age")
    println("In 5 years: ${age + 5}")
    
    // Type inference
    val pi = 3.14159          // Double
    val count = 42            // Int
    val active = true         // Boolean
    val greeting = "Hello"    // String
}

Null Safety

Kotlin
// Non-null (default)
var name: String = "Alice"
// name = null  // COMPILE ERROR!

// Nullable
var maybeName: String? = "Alice"
maybeName = null  // OK

// Safe call operator
println(maybeName?.length)  // null (no crash)

// Elvis operator (default if null)
val length = maybeName?.length ?: 0  // 0

// Not-null assertion (throws if null!)
// val forcedLength = maybeName!!.length  // Dangerous!

// Let (safe block for null)
maybeName?.let {
    println("Name is $it, length is ${it.length}")
} ?: println("Name is null")

Functions

Kotlin
// Basic function
fun add(a: Int, b: Int): Int {
    return a + b
}

// Expression body (single expression)
fun add(a: Int, b: Int) = a + b

// Named parameters
fun greet(name: String, greeting: String = "Hello") {
    println("$greeting, $name!")
}

greet("Alice")                  // Hello, Alice!
greet("Bob", greeting = "Hi")   // Hi, Bob!

// Varargs
fun sum(vararg numbers: Int): Int = numbers.sum()
sum(1, 2, 3, 4, 5)  // 15

// Extension function
fun String.isEmail(): Boolean = matches(Regex("^[\\w.-]+@[\\w.-]+\\.[a-z]{2,}$"))
"test@email.com".isEmail()  // true

// Higher-order function
fun apply(value: Int, transform: (Int) -> Int): Int = transform(value)
apply(5) { it * 2 }  // 10

Classes

Kotlin
// Data class (auto-generates equals, hashCode, toString, copy)
data class User(
    val name: String,
    val email: String,
    val age: Int
)

val alice = User("Alice", "alice@example.com", 28)
val bob = alice.copy(name = "Bob", age = 35)

// Regular class
class BankAccount(initialBalance: Double) {
    var balance = initialBalance
        private set  // Read-only from outside
    
    fun deposit(amount: Double) {
        require(amount > 0) { "Deposit must be positive" }
        balance += amount
    }
    
    fun withdraw(amount: Double): Boolean {
        if (amount > balance) return false
        balance -= amount
        return true
    }
}

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

fun <T> handleResult(result: Result<T>) = when (result) {
    is Result.Success -> "Data: ${result.data}"
    is Result.Error -> "Error: ${result.message}"
    is Result.Loading -> "Loading..."
}

Collections

Kotlin
val numbers = listOf(1, 2, 3, 4, 5)
val mutable = mutableListOf(1, 2, 3)

// Transformations
numbers.map { it * 2 }              // [2, 4, 6, 8, 10]
numbers.filter { it > 3 }           // [4, 5]
numbers.flatMap { listOf(it, it * 10) }  // [1, 10, 2, 20, ...]

// Aggregation
numbers.sum()                       // 15
numbers.average()                   // 3.0
numbers.maxOrNull()                 // 5

// Grouping
val words = listOf("apple", "banana", "avocado", "blueberry")
words.groupBy { it[0] }             // {a=[apple, avocado], b=[banana, blueberry]}

// Map
val scores = mapOf("Alice" to 95, "Bob" to 87)
scores["Alice"]                     // 95
scores.getOrDefault("Charlie", 0)   // 0

// Chaining
val result = numbers
    .filter { it % 2 == 0 }
    .map { it * it }
    .sum()  // 20 (4 + 16)

💡 Tip: Use val by default. Only use var when the value genuinely needs to change. Kotlin developers write ~80% val, ~20% var.

Next: Kotlin Null Safety