Kotlin Professional Certificate cheat sheet
Kotlin Professional Certificate · Keep the key ideas within reach.
Kotlin Language Fundamentals and Coding Tasks
val declares a read-only reference (assignment forbidden after init); var declares a mutable reference. val does not imply the object itself is immutable.
Type inference: the compiler infers the declared type from the initializer; explicit types are required for public API declarations where inference would expose an implementation type.
Nullability is part of the type system: String is non-null, String? is nullable. Safe call ?. returns null on null receiver; Elvis ?: supplies a fallback; !! throws NullPointerException.
Smart casts apply after a null check or is-check when the compiler can prove the value cannot change; a var captured in a closure or a custom getter blocks the smart cast.
when is an expression and, with a sealed/enum/boolean subject and exhaustive branches, requires no else. Branch conditions may be arbitrary expressions separated by commas.
String templates use $name for identifiers and ${expression} for anything else; raw strings delimited by triple quotes preserve newlines and need trimIndent()/trimMargin() to normalize.
Equality: == calls equals() (structural), === compares references (identity). Data classes generate equals/hashCode from constructor properties only.
Integer division truncates toward zero; use toDouble()/toBigDecimal() before dividing when fractional results are needed. Int overflow wraps silently.
Loops: for (i in 1..10) is inclusive, until is exclusive, downTo counts down, step changes the increment. Ranges on Int are IntRange values usable with in.
Object-Oriented and Functional Kotlin Programming
Primary constructor parameters without val/var are not properties; adding val/var promotes them to fields with generated getters (and setters for var).
open enables inheritance and overriding; override is mandatory on the overriding member. Members are final by default. abstract members have no body and force implementation.
Interfaces may declare properties (abstract or with a getter) and may provide default method bodies; a class can implement many interfaces but extend only one class.
sealed hierarchies restrict subclasses to the same package/module, enabling exhaustive when without else. sealed interface permits implementation by classes and enums.
data class generates equals, hashCode, toString, copy, and componentN; it cannot be abstract, open, sealed, or inner, and requires at least one constructor parameter.
object declares a singleton; companion object members are accessed via the class name and can hold factory functions; companion members are not static at the JVM level unless annotated @JvmStatic.
Higher-order functions take or return functions; function types are written (A, B) -> C. A lambda's last expression is its return value; the last parameter can move outside the parentheses.
Inline functions with inline lambda parameters avoid allocation and enable non-local return; reified type parameters require inline and allow T::class and is T checks at runtime.
Scope functions: let (it, returns lambda result), run (this, lambda result), with (this, lambda result), apply (this, receiver), also (it, receiver). Choose by receiver style and return value.
Kotlin Standard Library, Collections, and Coroutines
Read-only vs mutable: List/Set/Map interfaces expose no mutators; mutableListOf/mutableSetOf/mutableMapOf return MutableList etc. The read-only interface is a view, not a defensive copy.
Collection transformations return new collections: map, filter, flatMap, sortedBy, groupBy, associateBy, zip, partition. None mutate the source.
Sequences (asSequence) are lazy: intermediate operators build a pipeline and terminal operators (toList, first, count, sum) trigger evaluation, avoiding intermediate allocations on large inputs.
Aggregates: fold takes an explicit initial accumulator, reduce uses the first element and throws on empty. sumOf avoids boxing for numeric properties.
suspend functions can call other suspend functions and may be paused without blocking a thread; they can only be invoked from a coroutine or another suspend function.
Coroutine builders: launch returns a Job and ignores the result; async returns a Deferred whose value is obtained with await; runBlocking bridges blocking code and is unsuitable for production hot paths.
Structured concurrency: a parent scope waits for children; cancelling the parent cancels children; a failing child cancels siblings unless a SupervisorJob or supervisorScope isolates failures.
Dispatchers: Default for CPU-bound work, IO for blocking I/O, Main for UI, Unconfined for immediate execution. withContext switches dispatcher and returns a value.
Cancellation is cooperative: suspend functions check cancellation at suspension points; long CPU loops must call ensureActive() or yield() to remain cancellable. delay is cancellable, Thread.sleep is not.
Tooling, Testing, and IDE-Based Verification
Gradle Kotlin DSL uses build.gradle.kts; the Kotlin Gradle plugin (org.jetbrains.kotlin.jvm) sets the language version, and kotlin { jvmToolchain(n) } pins the JDK target.
Source sets: src/main/kotlin for production code, src/test/kotlin for tests; test dependencies use testImplementation so they stay off the main compile classpath.
kotlin.test provides multiplatform assertions (assertEquals, assertFailsWith, assertTrue) that map to the underlying framework; JUnit 5 requires useJUnitPlatform() in the test task.
Backtick test names allow spaces in JVM test method names, improving failure readability; @BeforeTest/@AfterTest (kotlin.test) or @BeforeEach/@AfterEach (JUnit 5) handle setup and teardown.
Coroutine tests use kotlinx-coroutines-test: runTest skips delays via a virtual time scheduler, and TestDispatcher/StandardTestDispatcher control execution order deterministically.
Turbine's test {} collects a Flow and asserts emissions in order, failing on timeout or unexpected completion, which verifies cold-flow behavior without manual collectors.
Mocking libraries (MockK) support suspend functions via coEvery/coVerify; plain every/verify cannot stub suspend calls correctly.
The IDE verifies code through the compiler frontend: inspections flag redundant null checks, unused symbols, and style issues; quick-fix (Alt+Enter) applies the suggested rewrite.
Debugging: conditional breakpoints, evaluate expression, and coroutine debug mode (-Dkotlinx.coroutines.debug) add coroutine names and creation stacks to thread dumps.