Section 1: Kotlin Fundamentals
Detailed Explanations with Complete Code Examples
1.1 Basic Syntax & Hello World
Core Concepts Explained
Kotlin’s syntax is concise and expressive. Here’s what you need to know:
val
vsvar
:- Use
val
for read-only (immutable) variables. - Use
var
for mutable variables (values can change).
- Use
- Type Inference: Kotlin infers types automatically (no need to declare
String
orInt
explicitly). - String Templates: Embed variables directly into strings using
$
or${}
. - Functions: Declare functions with
fun
. Single-expression functions omit braces.
Complete Code Example
data class Person(val name: String, val age: Int) // Data class for structured data
fun main() {
// Variables: val (immutable) vs var (mutable)
val greeting = "Hello, Kotlin!" // Type inferred as String
var counter = 0 // Mutable counter
counter += 1 // Valid: var can change
// String templates
val person = Person("Alice", 29)
println("${person.name} is ${person.age} years old") // "Alice is 29 years old"
// Function with parameters and return type
fun add(a: Int, b: Int): Int {
return a + b
}
println(add(5, 3)) // 8
// Single-expression function (shorthand)
fun isAdult(person: Person) = person.age >= 18
println(isAdult(person)) // true
}
1.2 Null Safety
Core Concepts Explained
Kotlin eliminates NullPointerException
(NPE) risks by design:
- Nullable Types: Explicitly declare nullable variables with
?
(e.g.,String?
). - Safe Calls (
?.
): Access properties/methods safely without NPEs. - Elvis Operator (
?:
): Provide default values for nullable expressions. - Non-null Assertion (
!!
): Forcefully unwrap nullable types (use sparingly!). - Scope Functions: Use
let{}
to execute code only if a value is non-null.
Complete Code Example
data class Address(val street: String?, val zipCode: Int?) // Street can be null
fun main() {
// Nullable type example
val nullableString: String? = null
// Safe call: returns null if nullableString is null
println(nullableString?.length) // null
// Elvis operator: default value if null
val length = nullableString?.length ?: 0
println(length) // 0
// Risky non-null assertion (throws NPE if null)
val forcedLength: String? = "Kotlin"
println(forcedLength!!.length) // 6
// let{} for safe scoping
val address = Address(null, 12345)
address.street?.let {
println("Street: $it") // Won't execute (street is null)
}
// Chaining safe calls with let{}
val person: Person? = Person("Bob", 31)
val street = person?.let {
// Imagine fetching address from a database
Address("Main Street", 67890)
}?.street ?: "Unknown"
println(street) // "Main Street"
}
1.3 Conditionals & Loops
Core Concepts Explained
Kotlin simplifies control flow with expressive constructs:
if
as Expression: Returns a value (no ternary operator needed).when
: A replacement forswitch
that works with any data type.- Ranges: Define sequences (e.g.,
1..10
,0 until 5
). - Loops:
for
iterates over ranges/collections;while
repeats until a condition fails.
Complete Code Example
fun main() {
val score = 85
// if-else as an expression (returns a value)
val grade = if (score >= 90) "A"
else if (score >= 80) "B"
else "C"
println(grade) // "B"
// when expression (like switch, but more powerful)
when (score) {
in 90..100 -> println("Excellent")
in 80..89 -> println("Good") // Matches here
else -> println("Needs improvement")
}
// Ranges and loops
for (i in 1..5) print("$i ") // 1 2 3 4 5
println()
// Step and until (exclusive upper bound)
for (i in 0 until 10 step 2) print("$i ") // 0 2 4 6 8
println()
// Iterate over a list
val names = listOf("Alice", "Bob", "Charlie")
for (name in names) print("$name ") // Alice Bob Charlie
println()
// while loop
var x = 3
while (x > 0) {
print("$x ") // 3 2 1
x--
}
}
1.4 Collections
Core Concepts Explained
Kotlin provides immutable and mutable collections:
- Immutable Collections: Created with
listOf()
,setOf()
,mapOf()
(can’t modify after creation). - Mutable Collections: Use
mutableListOf()
, etc., to add/remove elements. - Common Operations:
filter
: Select elements matching a condition.map
: Transform elements (e.g., extract a property).forEach
: Iterate over elements.
Complete Code Example
data class Book(val title: String, val year: Int)
fun main() {
// Immutable list
val books = listOf(
Book("1984", 1949),
Book("The Hobbit", 1937),
Book("Dune", 1965)
)
// Filter books published before 1950
val oldBooks = books.filter { it.year < 1950 }
println(oldBooks) // [Book(title=1984, year=1949), Book(title=The Hobbit, year=1937)]
// Map to extract titles
val titles = books.map { it.title }
println(titles) // [1984, The Hobbit, Dune]
// Mutable list (can add/remove elements)
val mutableBooks = mutableListOf<Book>()
mutableBooks.add(Book("Neuromancer", 1984))
mutableBooks += Book("Snow Crash", 1992)
println(mutableBooks.size) // 2
// forEach iteration
books.forEach { println("${it.title} (${it.year})") }
// Find first book matching a condition
val dune = books.firstOrNull { it.title == "Dune" }
println(dune) // Book(title=Dune, year=1965)
}
Key Takeaways
Concept | Why It Matters | Example |
---|---|---|
Immutable val | Prevents accidental mutations | val name = "Alice" |
Null Safety | Eliminates NPEs at compile time | val length = name?.length ?: 0 |
when Expression | Cleaner than switch | when (score) { ... } |
Collection Operations | Functional-style data processing | books.filter { ... } |
Section 2: Functional Programming in Kotlin
Detailed Explanations with Complete Code Examples
2.1 Lambdas & Higher-Order Functions
Core Concepts Explained
Functional programming treats functions as first-class citizens. Kotlin embraces this with:
- Lambdas: Anonymous functions defined with
{ }
.- Syntax:
{ param -> body }
(useit
for single parameters).
- Syntax:
- Higher-Order Functions: Functions that accept or return other functions.
- Function Types: Declared as
(Type1, Type2) -> ReturnType
.
Complete Code Example
data class Product(val name: String, val price: Double)
// Higher-order function: Takes a predicate lambda
fun filterProducts(products: List<Product>, predicate: (Product) -> Boolean): List<Product> {
return products.filter(predicate)
}
fun main() {
val products = listOf(
Product("Laptop", 999.99),
Product("Phone", 599.99),
Product("Headphones", 149.99)
)
// Lambda 1: Filter affordable products (price < 600)
val affordable = filterProducts(products) { it.price < 600 }
println(affordable) // [Product(name=Phone, price=599.99), Product(name=Headphones, price=149.99)]
// Lambda 2: Filter by name
val headphones = filterProducts(products) { it.name == "Headphones" }
println(headphones) // [Product(name=Headphones, price=149.99)]
// Function returning a lambda
val discount = 0.20
val applyDiscount: (Product) -> Double = { product -> product.price * (1 - discount) }
println("Discounted price: ${applyDiscount(products[0])}") // 799.992
}
2.2 Extension Functions
Core Concepts Explained
Extension functions let you add methods to existing classes without inheritance:
- Syntax:
fun ClassName.newMethod() { ... }
. - Accessed like regular methods.
- Great for utility functions or DSLs.
Complete Code Example
// Adds a "priceWithTax" method to Product
fun Product.priceWithTax(taxRate: Double): Double = this.price * (1 + taxRate)
// Adds a "findByName" method to List<Product>
fun List<Product>.findByName(name: String): Product? = this.firstOrNull { it.name == name }
fun main() {
val products = listOf(Product("Laptop", 999.99), Product("Phone", 599.99))
// Use extension function on Product
val laptop = products[0]
println("Laptop with tax: ${laptop.priceWithTax(0.10)}") // 1099.989
// Use extension function on List<Product>
val phone = products.findByName("Phone")
println(phone) // Product(name=Phone, price=599.99)
}
2.3 Function Composition
Core Concepts Explained
Combine simple functions to create complex logic:
- Predicate Composition: Combine conditions using
and
/or
/not
. - Custom Combinators: Create reusable logic with helper functions.
Complete Code Example
data class User(val name: String, val age: Int, val isAdmin: Boolean)
// Base predicates
val isAdult: (User) -> Boolean = { it.age >= 18 }
val isAdmin: (User) -> Boolean = { it.isAdmin }
val isNamedAlex: (User) -> Boolean = { it.name == "Alex" }
// Custom combinators (AND/OR)
infix fun <T> ((T) -> Boolean).and(other: (T) -> Boolean): (T) -> Boolean = { t ->
this(t) && other(t)
}
infix fun <T> ((T) -> Boolean).or(other: (T) -> Boolean): (T) -> Boolean = { t ->
this(t) || other(t)
}
fun main() {
val users = listOf(
User("Alex", 25, true),
User("Bob", 17, false),
User("Eve", 30, true)
)
// Compose predicates
val isAdultAdmin = isAdult and isAdmin
val isAlexOrAdmin = isNamedAlex or isAdmin
val adultAdmins = users.filter(isAdultAdmin)
println(adultAdmins) // [User(name=Alex, age=25, isAdmin=true), User(name=Eve, age=30, isAdmin=true)]
val alexOrAdmins = users.filter(isAlexOrAdmin)
println(alexOrAdmins) // [User(name=Alex, ...), User(name=Eve, ...)]
}
2.4 Kotlin Standard Library FP Tools
Core Concepts Explained
Kotlin’s standard library includes powerful FP operations for collections:
filter
: Select elements matching a condition.map
: Transform elements (e.g., extract a property).groupBy
: Create lookup maps by a key.fold
/reduce
: Aggregate values (e.g., sum, max).
Complete Code Example
data class Order(val id: Int, val amount: Double, val customer: String)
fun main() {
val orders = listOf(
Order(1, 100.0, "Alice"),
Order(2, 200.0, "Bob"),
Order(3, 150.0, "Alice")
)
// Filter: Orders over $150
val largeOrders = orders.filter { it.amount > 150 }
println(largeOrders) // [Order(id=2, amount=200.0, customer=Bob)]
// Map: Extract amounts
val amounts = orders.map { it.amount }
println(amounts) // [100.0, 200.0, 150.0]
// GroupBy: Orders per customer
val ordersByCustomer = orders.groupBy { it.customer }
println(ordersByCustomer["Alice"]) // [Order(id=1, ...), Order(id=3, ...)]
// Reduce: Total amount of all orders
val total = orders.map { it.amount }.reduce { acc, amount -> acc + amount }
println(total) // 450.0
// SumOf (idiomatic alternative)
val totalAlt = orders.sumOf { it.amount.toInt() } // For demonstration
println(totalAlt) // 450
}
Key Takeaways
Concept | Why It Matters | Example |
---|---|---|
Lambdas | Enable concise, inline logic | { it.price < 100 } |
Extension Functions | Extend classes without inheritance | fun List<Product>.findByName() |
Function Composition | Build complex logic from simple parts | isAdult and isAdmin |
groupBy /map | Transform and organize data efficiently | orders.groupBy { it.customer } |
Section 3: Object-Oriented Kotlin
Detailed Explanations with Complete Code Examples
3.1 Classes & Objects
Core Concepts Explained
Kotlin’s OOP model enhances Java’s with concise syntax and modern features:
- Primary Constructor: Declared directly in the class header.
- Secondary Constructors: Added with
constructor
keyword (less common). init
Blocks: Code executed during object initialization.- Properties: Combine fields and accessors (
get
/set
).
Complete Code Example
// Primary constructor with properties
class Person(val name: String, var age: Int) {
// Secondary constructor (delegates to primary)
constructor(name: String) : this(name, 0)
// init block runs at object creation
init {
println("Person $name created")
}
// Method
fun greet() = println("Hello, I'm $name")
// Custom property (no backing field)
val isAdult: Boolean
get() = age >= 18
}
fun main() {
val alice = Person("Alice", 29) // Prints "Person Alice created"
alice.greet() // "Hello, I'm Alice"
println(alice.isAdult) // true
val bob = Person("Bob") // Secondary constructor
println(bob.age) // 0 (default)
}
3.2 Data Classes & Destructuring
Core Concepts Explained
Data classes (data class
) automatically generate:
equals()
/hashCode()
: Value-based equality.toString()
: Human-readable string.copy()
: Create modified copies.- Destructuring: Break objects into variables.
Complete Code Example
data class Book(val title: String, val author: String, val year: Int)
fun main() {
val book = Book("Dune", "Frank Herbert", 1965)
// toString() auto-generated
println(book) // Book(title=Dune, author=Frank Herbert, year=1965)
// copy() with modified values
val updatedBook = book.copy(year = 2021)
println(updatedBook) // Book(title=Dune, ..., year=2021)
// Destructuring
val (title, author, year) = book
println("$title by $author ($year)") // Dune by Frank Herbert (1965)
// Equality check
val book2 = Book("Dune", "Frank Herbert", 1965)
println(book == book2) // true (values match)
}
3.3 Sealed Classes & Enums
Core Concepts Explained
- Sealed Classes:
- Define restricted hierarchies (subclasses in the same file).
- Exhaustive
when
checks (noelse
needed).
- Enums:
- Fixed set of constants.
- Can include properties and methods.
Complete Code Example
// Sealed class for payment methods
sealed class PaymentMethod {
data class CreditCard(val number: String, val expiry: String) : PaymentMethod()
data class PayPal(val email: String) : PaymentMethod()
object Cash : PaymentMethod()
}
// Enum for fixed categories
enum class Category(val displayName: String) {
ELECTRONICS("Electronics"),
BOOKS("Books"),
CLOTHING("Apparel")
}
fun processPayment(payment: PaymentMethod) {
when (payment) { // Exhaustive check (no else needed)
is PaymentMethod.CreditCard -> println("Processing card: ${payment.number}")
is PaymentMethod.PayPal -> println("Processing PayPal: ${payment.email}")
PaymentMethod.Cash -> println("Cash accepted")
}
}
fun main() {
val payment = PaymentMethod.CreditCard("1234-5678", "12/25")
processPayment(payment) // "Processing card: 1234-5678"
// Enum example
println(Category.BOOKS.displayName) // "Books"
}
3.4 Inheritance & Interfaces
Core Concepts Explained
- Inheritance:
- Classes are
final
by default (useopen
to allow inheritance). - Override methods with
override
.
- Classes are
- Interfaces:
- Define contracts (can include default implementations).
- Use
by
for delegation.
Complete Code Example
// Base class (open for inheritance)
open class Animal(val name: String) {
open fun speak() = println("$name makes a sound")
}
// Subclass overriding method
class Dog(name: String) : Animal(name) {
override fun speak() = println("$name barks!")
}
// Interface with default implementation
interface Logger {
fun log(message: String) = println("LOG: $message")
}
// Class implementing interface via delegation
class ConsoleLogger : Logger
class UserService(private val logger: Logger) : Logger by logger {
fun createUser(name: String) {
logger.log("User $name created")
}
}
fun main() {
val dog = Dog("Buddy")
dog.speak() // "Buddy barks!"
val userService = UserService(ConsoleLogger())
userService.createUser("Alice") // "LOG: User Alice created"
}
Key Takeaways
Concept | Why It Matters | Example |
---|---|---|
Data Classes | Auto-generated boilerplate code | data class Book(...) |
Sealed Classes | Exhaustive type checks | sealed class PaymentMethod |
open /override | Controlled inheritance | open class Animal; override fun speak() |
Interface Delegation | Reuse implementations | class UserService : Logger by logger |
Section 4: Advanced Kotlin
Detailed Explanations with Complete Code Examples
4.1 Coroutines & Asynchronous Programming
Core Concepts Explained
Coroutines simplify asynchronous code by managing threads and concurrency:
- Suspend Functions: Marked with
suspend
, can pause/resume execution without blocking threads. - Coroutine Builders:
launch
(fire-and-forget),async
(returns a result),runBlocking
(bridges blocking code). - Dispatchers: Define threads for execution (e.g.,
Dispatchers.IO
for network calls).
Complete Code Example
import kotlinx.coroutines.*
suspend fun fetchData(): String {
delay(1000) // Simulate network delay
return "Data fetched"
}
fun main() = runBlocking { // Creates a coroutine scope
println("Start: ${Thread.currentThread().name}")
// Launch a coroutine (fire-and-forget)
val job = launch(Dispatchers.IO) {
println("Fetching data: ${Thread.currentThread().name}")
val result = fetchData()
println(result)
}
// Async/await for results
val deferred = async(Dispatchers.Default) {
(1..10).sum()
}
println("Sum: ${deferred.await()}")
job.join() // Wait for coroutine to finish
println("End")
}
Output:
Start: main
Sum: 55
Fetching data: DefaultDispatcher-worker-1
Data fetched
End
4.2 Type-Safe Builders & DSLs
Core Concepts Explained
Kotlin’s DSLs (Domain-Specific Languages) use nested lambdas and extension functions:
@DslMarker
: Restricts implicit receivers in nested blocks.- Receiver Types: Lambdas with receivers (
ClassName.() -> Unit
) enable DSL syntax.
Complete Code Example
@DslMarker
annotation class HtmlDsl
class Html {
val elements = mutableListOf<String>()
fun body(block: Body.() -> Unit) {
elements.add("<body>")
elements.addAll(Body().apply(block).elements)
elements.add("</body>")
}
}
@HtmlDsl
class Body {
val elements = mutableListOf<String>()
fun h1(text: String) {
elements.add("<h1>$text</h1>")
}
fun p(text: String) {
elements.add("<p>$text</p>")
}
}
fun html(block: Html.() -> Unit): Html {
return Html().apply(block)
}
fun main() {
val page = html {
body {
h1("Welcome")
p("Hello, Kotlin DSL!")
}
}
println(page.elements.joinToString("\n"))
}
Output:
<body>
<h1>Welcome</h1>
<p>Hello, Kotlin DSL!</p>
</body>
4.3 Delegated Properties
Core Concepts Explained
Delegation offloads property logic to helper classes:
by lazy
: Initializes on first access.Observable
: Triggers callbacks on value changes.- Custom Delegates: Implement
ReadWriteProperty
/ReadOnlyProperty
.
Complete Code Example
import kotlin.properties.Delegates
class User {
// Lazy initialization
val bio by lazy {
println("Fetching bio...")
"Kotlin Developer"
}
// Observable property
var name: String by Delegates.observable("Anonymous") {
_, old, new -> println("$old → $new")
}
}
// Custom delegate for uppercase strings
class UppercaseDelegate : ReadWriteProperty<Any?, String> {
private var value = ""
override fun getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): String {
return value
}
override fun setValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>, value: String) {
this.value = value.uppercase()
}
}
fun main() {
val user = User()
println(user.bio) // "Fetching bio..." then "Kotlin Developer"
user.name = "alice" // Prints "Anonymous → ALICE"
println(user.name) // "ALICE"
var customName by UppercaseDelegate()
customName = "bob"
println(customName) // "BOB"
}
4.4 Reflection & Annotations
Core Concepts Explained
Reflection inspects code at runtime; annotations add metadata:
KClass
: Runtime representation of classes.- Annotations: Define metadata with
@Target
,@Retention
.
Complete Code Example
import kotlin.reflect.full.*
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Serializable
@Serializable
data class Person(val name: String, val age: Int)
fun serialize(obj: Any): String {
val klass = obj::class
if (klass.findAnnotation<Serializable>() == null) {
throw IllegalArgumentException("Class not serializable")
}
return klass.declaredMemberProperties.joinToString(", ") { prop ->
"${prop.name}=${prop.getter.call(obj)}"
}
}
fun main() {
val person = Person("Alice", 29)
println(serialize(person)) // "name=Alice, age=29"
val result = runCatching { serialize("NotSerializable") }
println(result.exceptionOrNull()) // IllegalArgumentException
}
4.5 Kotlin Multiplatform (KMP)
Core Concepts Explained
Share code across platforms (JVM, JS, Native):
- Common Module: Platform-agnostic code.
- Platform-Specific Code: Use
expect
/actual
declarations.
Complete Code Example
// Common module
expect fun currentTime(): String
class Greeter {
fun greet() = "Hello! Time is ${currentTime()}"
}
// JVM implementation
actual fun currentTime(): String {
return java.time.LocalDateTime.now().toString()
}
// JavaScript implementation (hypothetical)
// actual fun currentTime(): String = Date().toString()
Key Takeaways
Concept | Why It Matters | Example |
---|---|---|
Coroutines | Non-blocking async code | launch(Dispatchers.IO) { ... } |
DSLs | Domain-specific syntax | html { body { ... } } |
Delegates | Reusable property logic | var name by Delegates.observable(...) |
Annotations | Metadata for reflection | @Serializable class Person |
Section 5: Practical Kotlin
Real-World Applications and Best Practices
5.1 Unit Testing
Core Concepts Explained
Testing is critical for robust code. Kotlin works seamlessly with:
- JUnit 5: Modern testing framework.
- MockK: Mocking library for Kotlin (better than Mockito for coroutines/DSL support).
- Coroutine Testing: Use
runTest
to handle async code.
Complete Code Example
import io.mockk.*
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class UserService(private val userRepository: UserRepository) {
suspend fun getUserName(id: Int): String? {
return userRepository.getUser(id)?.name
}
}
interface UserRepository {
suspend fun getUser(id: Int): User?
}
data class User(val id: Int, val name: String)
class UserServiceTest {
private val userRepository = mockk<UserRepository>()
private val userService = UserService(userRepository)
@Test
fun `getUserName returns name when user exists`() = runBlocking {
// Stub the repository response
coEvery { userRepository.getUser(1) } returns User(1, "Alice")
val result = userService.getUserName(1)
assertEquals("Alice", result)
// Verify interaction
coVerify { userRepository.getUser(1) }
}
@Test
fun `getUserName returns null for invalid user`() = runBlocking {
coEvery { userRepository.getUser(2) } returns null
assertEquals(null, userService.getUserName(2))
}
}
5.2 Android-Specific Kotlin
Core Concepts Explained
Kotlin is the preferred language for Android, with modern tools:
- Jetpack Compose: Declarative UI framework.
- ViewModel: Manages UI-related data.
- StateFlow: Observables for state management.
Complete Code Example
// ViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
class CounterViewModel : ViewModel() {
private val _count = MutableStateFlow(0)
val count: StateFlow<Int> = _count.asStateFlow()
fun increment() {
_count.value++
}
}
// Composable UI
@Composable
fun CounterScreen(viewModel: CounterViewModel) {
val count by viewModel.count.collectAsState()
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Count: $count")
Button(onClick = viewModel::increment) {
Text("Increment")
}
}
}
5.3 Spring Boot with Kotlin
Core Concepts Explained
Kotlin simplifies Spring Boot development with:
- Null-Safe APIs: Reduce runtime errors.
- Coroutine Support: Non-blocking endpoints.
- Kofu DSL: Functional bean configuration.
Complete Code Example
@RestController
class GreetingController {
@GetMapping("/greeting")
suspend fun greeting(@RequestParam name: String?) = coroutineScope {
val userName = name ?: "Guest"
mapOf("message" to "Hello, $userName!")
}
}
// Application.kt
@SpringBootApplication
class Application {
@Bean
fun router() = router {
GET("/api/hello") { ok().body("Hello from Kotlin!") }
}
}
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
5.4 Best Practices & Idioms
Core Concepts Explained
Write idiomatic Kotlin with these patterns:
- Immutability: Prefer
val
overvar
. - Expression-Bodied Functions: Use
= ...
for simple functions. - Scope Functions:
apply
,also
,let
,run
,with
.
Complete Code Example
data class Config(var host: String = "", var port: Int = 0)
fun main() {
// apply: Initialize objects
val config = Config().apply {
host = "localhost"
port = 8080
}
// let: Null-safe transformation
val nullableString: String? = "Kotlin"
val length = nullableString?.let {
it.length // Only executed if non-null
} ?: 0
// Idiomatic data processing
val numbers = listOf(1, 2, 3)
val doubled = numbers
.filter { it > 1 }
.map { it * 2 }
// Destructuring in lambdas
val users = listOf(User(1, "Alice"), User(2, "Bob"))
users.forEach { (id, name) -> println("$id: $name") }
}
Key Takeaways
Concept | Why It Matters | Example |
---|---|---|
MockK | Kotlin-friendly mocking | coEvery { ... } returns ... |
Jetpack Compose | Declarative Android UI | Text("Count: $count") |
Spring Coroutines | Non-blocking APIs | suspend fun greeting() |
Scope Functions | Concise object handling | config.apply { ... } |