Step 1 • Setup
Setup — IntelliJ IDEA, Gradle, and Kotlin Playground beginner Kotlin runs on the JVM, compiles to JavaScript, and compiles to native binaries (Kotlin Multiplatform). JVM Kotlin (this roadmap) requires a JDK (JDK 17 LTS recommended). IntelliJ IDEA (free Community Edition) is the best IDE — built by JetBrains who created Kotlin, native support. Kotlin Playground (play.kotlinlang.org) for quick experiments without setup. Build tools: Gradle with Kotlin DSL (build.gradle.kts — uses Kotlin syntax instead of Groovy, better IDE support) or Maven. REPL: kotlinc command for an interactive shell. Understand that Kotlin is 100% interoperable with Java — you can call any Java library from Kotlin and vice versa. This interoperability is why Kotlin adoption in existing Java codebases is seamless.
Language Kotlin 2h Step 2 • Foundations
Syntax — Variables, Types, and Control Flow beginner Kotlin is concise and expressive. Variables: val (immutable — prefer this), var (mutable). Type inference — val name = 'Alice' infers String. Explicit types: val age: Int = 30. Basic types: Int, Long, Double, Float, Boolean, Char, String, Any (root type), Unit (like void), Nothing (never returns). String templates: "Hello, $name — you are ${age + 1} next year". Control flow: if/else as expression (val result = if (x > 0) 'positive' else 'negative'), when (Kotlin's switch — exhaustive, supports ranges and type checks), for loops (for (i in 1..10), for (item in list)), while, do-while. ranges: 1..10 (inclusive), 1 until 10 (exclusive), 10 downTo 1, step 2.
Language Kotlin 5h Step 3 • Foundations
Null Safety — Kotlin's Killer Feature beginner Kotlin eliminates NullPointerExceptions at compile time — the type system tracks nullability. Non-nullable types (String) cannot hold null — the compiler refuses. Nullable types (String?) can hold null. Operators: safe call (?.) — user?.address?.city returns null instead of throwing if any part is null. Elvis operator (?:) — val name = user?.name ?: 'Unknown' (provide a default). Not-null assertion (!!) — throw NPE if null (use only when you know it's not null — treat as a code smell). Smart casts — after an if (x != null) check, the compiler knows x is non-null in that branch. let with safe call: user?.let { doSomethingWith(it) }. Interop with Java: @Nullable/@NotNull annotations in Java map to Kotlin nullable types.
Language Kotlin 5h Step 4 • OOP
OOP — Classes, Data Classes, and Sealed Classes intermediate Kotlin classes are concise — constructor parameters can be properties (class Person(val name: String, var age: Int)). Data classes auto-generate equals(), hashCode(), toString(), copy() — perfect for DTOs and value objects (data class User(val id: Long, val name: String)). Sealed classes define a closed hierarchy — subclasses must be in the same package/file, the compiler knows all subtypes (making when exhaustive without else). sealed class Result with Success and Error subclasses is idiomatic. Object declaration — singleton: object Config { val apiUrl = '...' }. Companion object — static members in a class (companion object { fun create(): MyClass }). Enum classes for a fixed set of constants. Abstract classes and interfaces (interfaces can have default method implementations).
Language Kotlin 7h Step 5 • intermediate
Kotlin/Java Interoperability intermediate Call Java code from Kotlin seamlessly — understand platform types (the ! annotation), null safety with @Nullable/@NonNull Java annotations, and SAM conversions (single abstract method interfaces become lambdas). Call Kotlin from Java: use @JvmStatic for companion object methods, @JvmOverloads for default parameters, @JvmField to expose properties as fields. Use existing Java libraries in Kotlin projects, and understand how Kotlin compiles to JVM bytecode.
Backend Kotlin 5h Step 6 • Functional
Functions — Extensions, Higher-Order, and Lambdas intermediate Kotlin treats functions as first-class citizens. Extension functions — add methods to existing classes without inheritance (fun String.isPalindrome(): Boolean = this == this.reversed()). This works on any class, including Java classes and standard library types. Higher-order functions — take or return functions. Lambda syntax: val double = { x: Int -> x * 2 }. Trailing lambda convention — if the last param is a lambda, move it outside parentheses (list.filter { it > 0 }). Function types — (Int) -> Int, (String, Int) -> Boolean. Inline functions (inline keyword) — the compiler copies the function body at call sites, enabling non-local returns from lambdas. Default and named parameters eliminate method overloading.
Language Kotlin 6h Step 7 • Standard Library
Collections — Functional Operations and Sequences intermediate Kotlin's standard library has powerful collection operations. Immutable vs mutable: listOf() vs mutableListOf(), mapOf() vs mutableMapOf(). Operations: map, filter, reduce, fold, groupBy, partition, flatMap, zip, associate, any/all/none, first/firstOrNull, sortedBy/sortedWith, distinctBy, take/drop. Sequences (asSequence()) are lazy — operations are chained and evaluated only when a terminal operation is called (like streams in Java) — use for large collections to avoid intermediate list creation. Destructuring declarations — val (a, b) = pair, for ((key, value) in map). List comprehensions via buildList { }. The difference between map vs mapNotNull (filters nulls automatically).
Language Kotlin 5h Step 8 • Idiomatic Kotlin
Scope Functions — let, run, with, apply, also intermediate Scope functions execute a block with an object in scope — they differ in how the object is referenced (this vs it) and what they return (the object vs the lambda result). let — object is it, returns lambda result — use for null-safe operations (user?.let { ... }) and transformations. run — object is this, returns lambda result — use for object initialization and computing a result. with — object is this, returns lambda result — use when you have a non-null object and want to call multiple methods on it. apply — object is this, returns the object — use for builder-style initialization. also — object is it, returns the object — use for side effects (logging) in a chain. Choosing the right scope function is a marker of idiomatic Kotlin.
Language Kotlin 4h Step 9 • Concurrency
Coroutines — Asynchronous Programming advanced Coroutines are Kotlin's answer to async/await — lightweight threads managed by the runtime (launch thousands for pennies in memory vs OS threads). suspend functions can be paused and resumed without blocking a thread. launch { } starts a coroutine (fire-and-forget), async { } starts one that returns a Deferred (like a future — await() the result). CoroutineScope and coroutineContext manage coroutine lifecycle — always use structured concurrency (coroutines are children of a scope, cancelled when the scope is cancelled). Dispatchers: IO (blocking I/O), Default (CPU-intensive), Main (Android UI thread). withContext switches dispatchers within a coroutine. Kotlin coroutines power Ktor, Spring WebFlux, and Android's ViewModel.
Language Kotlin 9h Step 10 • Concurrency
Flow — Asynchronous Streams advanced Flow is a cold asynchronous stream — values are produced lazily, the producer doesn't run until collected. flow { emit(value) } creates a Flow. Operators: map, filter, take, transform, flatMapLatest (cancel previous on new value — perfect for search), combine (merge two flows), zip, debounce, distinctUntilChanged, buffer, conflate. Collect at the end: flow.collect { value -> ... }. StateFlow — a hot state holder (like LiveData — always has a value, replays last value to new collectors). SharedFlow — a hot broadcast stream (multiple collectors, configurable replay). MutableStateFlow for UI state, MutableSharedFlow for one-shot events. Flow context preservation — don't use withContext inside a flow builder (use flowOn instead).
Language Kotlin 7h Step 11 • Testing
Testing — JUnit 5, MockK, and Kotest intermediate Kotlin testing uses JUnit 5 (JVM standard) with idiomatic Kotlin additions. MockK is Kotlin-native mocking (unlike Mockito which struggles with final classes — all Kotlin classes are final by default). MockK: every { mock.method() } returns value, verify { mock.method() was called }. Kotest is a pure-Kotlin test framework with multiple styles (DescribeSpec, BehaviorSpec, StringSpec — more expressive than JUnit annotations). kotlin.test for multiplatform tests. Testing coroutines requires kotlinx-coroutines-test — TestCoroutineDispatcher, runTest (replaces runBlocking in tests), advanceTimeBy for time-based tests. Turbine for testing Flow emissions (turbine.test { assertItem(), awaitComplete() }).
Language Kotlin 6h Step 12 • Applications
Android with Kotlin and Jetpack Compose intermediate Kotlin is the official language for Android (replacing Java). Jetpack Compose is Android's modern declarative UI toolkit — components are Composable functions annotated with @Composable. State: remember { mutableStateOf(value) } for local state, ViewModel + StateFlow for screen state (MVVM pattern). Navigation: NavController, NavHost, composable routes. LazyColumn/LazyRow for lists (RecyclerView replacement). Material 3 components. Coroutines in Android: viewModelScope.launch (cancelled when ViewModel is cleared), lifecycleScope.launch (cancelled when lifecycle is destroyed). Retrofit + Kotlin coroutines for HTTP. Room database with coroutine support. Hilt for dependency injection.
Mobile Kotlin 8h Step 13 • Applications
Kotlin with Spring Boot intermediate Kotlin and Spring Boot are a powerful backend combination — all Spring annotations work, but Kotlin makes them more concise. Data classes work perfectly as request/response DTOs (no Lombok needed). Declare @RestController, @Service, @Repository as regular Kotlin classes. All-open compiler plugin (required because Spring proxies need open classes — Spring Boot configures this automatically). Jackson Kotlin module for correct data class serialization. Spring Data with Kotlin: coroutine repositories (CoroutineCrudRepository) for non-blocking database access. Spring WebFlux with Kotlin coroutines — suspend functions instead of Mono/Flux. @Transactional works on suspend functions with spring-tx.
Backend Kotlin 6h Step 14 • Backend
Ktor — Kotlin-Native Web Framework intermediate Ktor is JetBrains' async, lightweight Kotlin web framework — no magic, no reflection, 100% Kotlin DSL. Embedded servers: Netty or CIO engine. Routing DSL: get, post, put, delete with route() blocks and path parameters. Plugins (install): ContentNegotiation (kotlinx.serialization for JSON), Authentication (JWT, session), Compression, CORS, StatusPages for error handling. Request validation with a validation plugin or manual checks. Ktor is coroutine-native — all handlers are suspend functions. Ktor Client for multiplatform HTTP (same API on Android, iOS, JVM). Testing with testApplication { } — no real server needed. Ktor is the natural choice for Kotlin Multiplatform backends.
Backend Kotlin 6h Step 15 • Advanced
Kotlin Multiplatform — Share Code Across Platforms advanced Kotlin Multiplatform (KMP) shares code between Android, iOS, Web, and Desktop — write business logic once, implement UI natively. Project structure: commonMain (shared — pure Kotlin, no platform APIs), androidMain, iosMain, jvmMain. expect/actual mechanism: declare expect fun getPlatformName(): String in commonMain, provide actual implementations in each platform source set. Ktor for multiplatform HTTP. SQLDelight for multiplatform SQLite (generates type-safe queries). Compose Multiplatform extends Jetpack Compose to iOS and Desktop. KMP is production-stable for Android + iOS sharing. Kotlin/WASM for the browser is experimental. Start with sharing just the data and domain layers — don't try to share everything.
Language Kotlin 7h