Kotlin
Kotlin as interviewers actually probe it: null safety baked into the type system, data classes and sealed hierarchies, extension functions and DSL-shaped lambdas, structured-concurrency coroutines, and the Java interop seams underneath it all. It is the default language for Android and a common choice for JVM backends, so most JVM teams ask about it.
on this pageshowhide
guide
overview
~2 minKotlin interviews check whether you write the language the way it was designed or as Java with shorter syntax. Expect the opening minutes on how the compiler tracks absence, followed by the object model — data classes, sealed hierarchies, objects and companions — and then idiomatic function style: extensions, scope functions, lambdas with receivers. Any role that touches asynchronous work, whether an Android screen or a JVM service, spends a long stretch on coroutines and Flow, where cancellation and error propagation expose who has shipped concurrent code and who has only read about it. Senior rounds turn to trade-offs: why `inline` exists, when a sequence beats a list, why the ecosystem prefers generating code at compile time to reflecting at runtime. The hub follows those seams. The language core is [Fundamentals](/topics/lang-kotlin-fundamentals), [Null Safety](/topics/lang-kotlin-null-safety), the [Type System](/topics/lang-kotlin-type-system), [Classes & Objects](/topics/lang-kotlin-classes), [Functions](/topics/lang-kotlin-functions) and [Functional Features](/topics/lang-kotlin-functional). Everyday library work sits in [Collections & Sequences](/topics/lang-kotlin-collections), the [Standard Library](/topics/lang-kotlin-stdlib) and [DSLs & Type-Safe Builders](/topics/lang-kotlin-dsls). Concurrency is [Coroutines](/topics/lang-kotlin-coroutines) and then [Flow](/topics/lang-kotlin-flow). The platform boundaries are [Java Interop](/topics/lang-kotlin-interop) and [Multiplatform](/topics/lang-kotlin-multiplatform), and the working-engineer layer is [Tooling & Build](/topics/lang-kotlin-tooling), [Testing](/topics/lang-kotlin-testing) and [Reflection, Annotations & Serialization](/topics/lang-kotlin-reflection). Learn it roughly in that order. Fundamentals and null safety come first, because almost every later answer assumes you read `if` as an expression and `T?` as a distinct type. Classes and functions next, since they are the bulk of daily code, then functional features and collections. Leave coroutines until lambdas, receivers and inline functions feel routine: the concurrency API is built from them, and gaps there make its questions look harder than they are. Pick up interop alongside the core, because platform types appear the first time you call a Java library. Multiplatform, tooling and testing carry the most weight when the role names them: a mobile team sharing code with iOS, or a backend team that expects you to own the build.
primer
### Absence is a type, not a runtime accident Kotlin splits every type into a non-null and a nullable variant, and the compiler refuses unchecked use of the nullable one. The operators (`?.`, `?:`, `!!`), smart casts after a check, and `lateinit` are all tools for moving a value from one side of that split to the other. The guarantee is weakest at the Java boundary, where values arrive as platform types and the checking is on you. ### Closed and read-only by default Classes and members are `final` unless marked `open`; `val` is the binding you reach for first; `List`, `Set` and `Map` expose no mutators. These choices invert Java's habits, and interviewers probe the consequences: frameworks that proxy classes by subclassing them, read-only views that are not truly immutable, and `sealed` hierarchies that let the compiler check a `when` for exhaustiveness. ### Almost everything is an expression `if`, `when` and `try` produce values, functions can have expression bodies, and `Nothing` is the type of an expression that never completes, such as `throw`. This is why Kotlin reads as a chain of values rather than a sequence of assignments, and why so many idioms fit on one line. ### The compiler writes the boilerplate — know what it writes Properties get generated accessors, data classes get generated equality and copying, `by` generates forwarding for interface and property delegation, and default arguments stand in for overload sets. Many intermediate questions are really asking what the generated code looks like and which inputs it uses. ### Functions are values, and receivers are the trick Extension functions are static functions with a member-style call site: they add nothing to the class and are resolved against the declared type. Lambdas with receivers let a block run as if it were inside another object; scope functions, builders and most Kotlin DSLs rest on that one feature. `inline` makes the style cheap by removing the lambda object, and it also unlocks non-local returns and `reified` type parameters. ### Concurrency is structured A coroutine is a computation that can suspend without holding a thread, and it is launched from a scope. Scopes form a parent–child tree, so cancellation and failures travel along it instead of leaking. Cancellation is cooperative: code has to reach a cancellable suspension point or check for cancellation itself. Flow extends the same model to streams — cold by default, with `StateFlow` and `SharedFlow` for hot, shared values. ### Compile time over run time Where many Java libraries reflect at runtime, Kotlin's ecosystem tends to generate code during compilation: the serialization plugin, KSP processors, reified generics, contracts that feed smart casts. Expect a senior interviewer to ask why.
- Nullable type
- A type written with a trailing question mark that admits null; the compiler requires a check or a null-handling operator before its members can be used.
- Platform type
- The type Kotlin assigns to a Java value whose nullability is unknown; the compiler lets you treat it as nullable or non-null and does not check.
- Smart cast
- Automatic narrowing of a variable's type after a null test or type test, valid only while the compiler can prove the value cannot change in between.
- Data class
- A class whose primary-constructor properties drive compiler-generated equals, hashCode, toString, copy and componentN functions.
- Sealed hierarchy
- A class or interface whose direct subtypes are all known at compile time, so a when expression over it can be checked for exhaustiveness.
- Value class
- A single-property wrapper, annotated JvmInline on the JVM, that the compiler represents as the underlying value where it can, giving a distinct type without an allocation.
- Companion object
- An object declared inside a class and reached through the class name; Kotlin's stand-in for Java static members, though it is a real instance.
- Extension function
- A function declared for a receiver type outside that type's source, called with member syntax but resolved statically.
- Lambda with receiver
- A function literal whose body runs with a given object as this, typed like A.() -> B; the basis of scope functions and DSLs.
- Scope function
- One of let, run, with, apply and also: small inline helpers that run a block on an object and differ in how they expose it and what they return.
- Inline function
- A function whose body, together with the bodies of its lambda arguments, the compiler substitutes at each call site, avoiding lambda objects.
- Reified type parameter
- A type parameter of an inline function that keeps its concrete type at the call site, so the body can use it in type checks and class references.
- Declaration-site variance
- Marking a type parameter out (produced) or in (consumed) on the class itself, so every use gets the subtyping without use-site wildcards.
- Nothing
- The bottom type, which has no values; the type of throw and of functions that never return, and a subtype of every other type.
- Suspend function
- A function that may pause without blocking its thread; it can be called only from a coroutine or from another suspend function.
- Structured concurrency
- The rule that coroutines live inside scopes whose lifetimes bound them, so cancellation and failures propagate through a parent-child tree.
- Dispatcher
- The coroutine context element that decides which thread or thread pool a coroutine runs on.
- StateFlow
- A hot flow that always holds a current value and hands it to each new collector; the usual holder for observable UI or service state.
- expect and actual
- The Multiplatform mechanism for declaring an API in common code and supplying a platform-specific implementation in each target's source set.
- KSP
- Kotlin Symbol Processing: an API for annotation processors that reads Kotlin declarations directly, replacing kapt's slower route through generated Java stubs.
The sections stack. The core — fundamentals, null safety, the type system, classes, functions — defines what a value is and how it can be shaped. Functional features and collections sit directly on it: higher-order functions and inline lambdas are what make the collection operators both readable and cheap, and sequences are the same operators made lazy. DSLs are receivers and lambdas pushed to their limit, which is why [Scope Functions](/topics/lang-kotlin-functions-scope-functions) and [Receiver Lambdas](/topics/lang-kotlin-dsls-receiver-lambdas) are two views of one feature. Coroutines reuse all of it. A coroutine builder is a higher-order function taking a suspending lambda with the scope as its receiver; the context is a small keyed set of elements; cancellation travels as an exception. [Flow](/topics/lang-kotlin-flow) is then a suspending producer plus operators that look like the collection ones, so a question comparing Flow operators with list operators is testing whether you see the shared shape and the difference in timing. The outer ring is where Kotlin meets other systems. [Java Interop](/topics/lang-kotlin-interop) is where the null guarantee and final-by-default meet code that shares neither; [Multiplatform](/topics/lang-kotlin-multiplatform) is where common code loses the JDK and leans on the standard library and kotlinx libraries instead. Tooling, testing and serialization are practical consequences: some compiler plugins exist only to relax the language's defaults for frameworks, coroutine tests need their own scheduler because real threads and real time make results nondeterministic, and serialization is code generation rather than reflection. A small example where several core ideas meet: ```kotlin data class User(val email: String, val nickname: String?) sealed interface LoadState { data object Loading : LoadState data class Loaded(val user: User) : LoadState data class Failed(val cause: Throwable) : LoadState } fun LoadState.label(): String = when (this) { LoadState.Loading -> "loading" is LoadState.Loaded -> user.nickname ?: user.email is LoadState.Failed -> cause.message ?: "unknown error" } ``` The sealed interface lets `when` be exhaustive with no `else` branch; each `is` branch smart-casts `this`, so `user` and `cause` are reachable directly; the extension adds `label()` without touching the hierarchy; and the Elvis operator settles the nullable fields. Add a subtype and this `when` stops compiling until it handles the new case — the property interviewers mean when they call sealed types a modelling tool.
- Fundamentals →
Expressions, val-first bindings, types without implicit conversion and the two equality operators are assumed by every other section.
- Null Safety →
Interviewers reach for it earliest; nullable types, the operators and smart casts reappear in almost every later answer.
- Classes & Objects →
The largest everyday surface: constructors, properties, data and sealed classes, objects. Most modelling questions start here.
- Functions →
Extensions, default arguments and scope functions are what make code read as Kotlin rather than translated Java.
- Functional Features →
Lambdas, function types and inline are the machinery that collections, DSLs and coroutines are built from; learn it before them.
- Coroutines →
With the core solid, move to concurrency: suspension, builders and dispatchers, then structured cancellation and exception handling.
Sprinkling the not-null assertion operator to silence the compiler: it moves the crash to runtime, and interviewers read it as not understanding Null Safety.
Treating values returned from Java as safe: they are platform types, and a wrong assumption surfaces as a crash far from where the null came in.
Calling a read-only List immutable: the interface hides mutators, but the object behind it may be a mutable list that another reference still changes.
Expecting an extension function to override a member or dispatch polymorphically: it is resolved against the declared type, and a member with the same signature wins.
Declaring state in a data class body and expecting it in equality or copy: the generated members see only primary-constructor properties.
Launching into GlobalScope to run something in the background: the work escapes every lifecycle, so nothing cancels it and its failure reaches no parent.
Catching Exception broadly inside a coroutine without rethrowing the cancellation exception: the coroutine can ignore its own cancellation and keep working after its scope is gone.
Making blocking calls on a dispatcher meant for CPU work: each call parks a shared thread and can starve other coroutines; blocking I/O belongs on a dispatcher sized for it.
Answering a Flow question with list thinking: a cold flow reruns its producer for every collector, so collecting it twice does the work twice.
This guide assumes Kotlin 2.x, where the K2 compiler is the default. Most language answers read the same on late 1.x releases, but interviewers still ask about the milestones that changed how code is written: - **1.3** — coroutines became stable, and inline classes appeared as an experimental feature. - **1.5** — value classes became the stable form of inline classes, and sealed interfaces arrived. - **1.7.20** — Kotlin/Native switched to its new memory manager by default, retiring the rule that objects had to be frozen before being shared across threads. - **1.9** — `data object` declarations and the `entries` property on enums became stable. - **1.9.20** — Kotlin Multiplatform was declared stable. - **2.0** — K2 became the default compiler, with faster compilation and smart casts that work in more places. The keyword change around inline classes is the one that still confuses candidates reading older material: ```kotlin // 1.3–1.4, experimental inline class OrderId(val raw: String) // 1.5 onward @JvmInline value class OrderId(val raw: String) ``` The idea did not change, only the spelling; when an older answer or article says inline class, read value class.
JetBrains makes the language, its IDE support and the kotlinx libraries for coroutines, serialization and date-time. Interviewers expect you to place Kotlin in three settings. On **Android**, Kotlin is the default language; Jetpack Compose is written for it, and coroutines and Flow are the usual async tools in new code, a role RxJava used to fill. On the **JVM backend**, it runs on Spring Boot, which supports it directly, and on Ktor, JetBrains' own server framework; the Gradle Kotlin DSL is a common first contact. For **shared mobile logic**, Kotlin Multiplatform competes with cross-platform UI frameworks: it shares business logic and lets each platform keep a native UI, with Compose Multiplatform as the option for sharing UI as well. The comparison that comes up most is with modern **Java**. Records, sealed types, pattern matching and virtual threads have narrowed the gap, so a strong answer names what remains: nullability in the type system, extension functions and receivers, and the structured cancellation coroutines give you, which virtual threads alone do not. Scala is the other expressive JVM language a candidate may be asked to contrast it with.
explore
- Fundamentals139 questions
- How Kotlin Does Basic Syntax5 questions
- Syntax Basics27 questions
- Variables26 questions
- Basic Types30 questions
- Control Flow31 questions
- Operators20 questions
- Null Safety87 questions
- How Kotlin Models Absence5 questions
- Nullable Types20 questions
- Null-Handling Operators25 questions
- Smart Casts15 questions
- Platform Types13 questions
- lateinit and isInitialized9 questions
- Type System110 questions
- How Kotlin Does Types5 questions
- Special Types & the Type Lattice30 questions
- Generic Declarations20 questions
- Variance & Projections20 questions
- Reification & Erasure20 questions
- Type Aliases15 questions
- Classes & Objects173 questions
- How Kotlin Does Classes & Objects5 questions
- Class Declarations & Members36 questions
- Data Classes21 questions
- Sealed Types20 questions
- Value / Inline Classes15 questions
- Enum Classes20 questions
- Objects & Companions21 questions
- Inheritance & Interfaces25 questions
- Delegation10 questions
- Functions120 questions
- How Kotlin Does Functions6 questions
- Declaration Forms40 questions
- Extension Functions & Properties30 questions
- Scope Functions25 questions
- Special Function Forms19 questions
- Functional Features110 questions
- How Kotlin Does Functions-as-Values5 questions
- Lambdas & Anonymous Functions25 questions
- Function Types20 questions
- Callable References15 questions
- Inline Machinery30 questions
- Higher-Order Functions15 questions
- Collections & Sequences122 questions
- How Kotlin Does Collections & Sequences5 questions
- Collection Types & Builders30 questions
- Collection Operations32 questions
- Sequences & Lazy Pipelines25 questions
- Ranges & Progressions15 questions
- Tuples, Iterators & Ordering Contracts15 questions
- Coroutines144 questions
- How Kotlin Does Coroutines5 questions
- Suspension Mechanics15 questions
- Coroutine Builders25 questions
- Context & Dispatchers15 questions
- Structured Concurrency25 questions
- Cancellation19 questions
- Exception Handling20 questions
- Synchronization Primitives20 questions
- Flow106 questions
- How Kotlin Does Reactive Streams5 questions
- Cold Flows21 questions
- Operators20 questions
- Hot Flows15 questions
- Backpressure15 questions
- Channel-Backed Flows15 questions
- Error & Completion15 questions
- Standard Library137 questions
- How Kotlin Does Its Standard Library5 questions
- Result & Error Handling20 questions
- Delegated Properties25 questions
- Time & Duration20 questions
- Text & Regex16 questions
- I/O & Files15 questions
- Contracts15 questions
- Misc Helpers21 questions
- DSLs & Type-Safe Builders66 questions
- How Kotlin Builds Internal DSLs5 questions
- Receiver Lambdas20 questions
- Builder Patterns20 questions
- DSL Examples & Idioms21 questions
- Java Interop116 questions
- How Kotlin Interops With Java5 questions
- Calling Java From Kotlin30 questions
- Calling Kotlin From Java31 questions
- Type Mapping Mechanics25 questions
- Boundary Pitfalls25 questions
- Multiplatform111 questions
- How Kotlin Does Multiplatform5 questions
- expect / actual Declarations15 questions
- Source Sets20 questions
- Compilation Targets25 questions
- Kotlin/Native Mechanics20 questions
- Multiplatform Libraries16 questions
- JavaScript Interop10 questions
- Tooling & Build91 questions
- How Kotlin Does Build Tooling5 questions
- Gradle Kotlin DSL20 questions
- Annotation Processing20 questions
- Compiler25 questions
- Quality Tooling21 questions
- Testing107 questions
- How Kotlin Does Testing6 questions
- kotlin.test21 questions
- MockK25 questions
- Kotest20 questions
- Coroutine Testing20 questions
- Flow Testing15 questions
- Reflection, Annotations & Serialization137 questions
- How Kotlin Does Reflection & Metaprogramming5 questions
- Kotlin Reflection (kotlin-reflect)40 questions
- Annotations30 questions
- Serialization Core (kotlinx.serialization)25 questions
- Serialization Formats37 questions
questions
1,876 · 16 sectionsWhat does 7 / 2 evaluate to in Kotlin, and how do you get a fractional result instead?
basics
~10 s7 / 2 is 3, because dividing two whole numbers throws away the part after the decimal point. To get 3.5, make at least one number a decimal, like 7.0 / 2.
In Kotlin, is Char a numeric type? How do you get the numeric (code-point) value of a Char, and how do you turn a digit Char like '7' into the Int 7?
basics
~10 sNo. A Char in Kotlin is a character, not a number. To get its underlying code you use .code, and to turn a digit character like '7' into the number 7 you use .digitToInt().
What is `const val` in Kotlin, and how does it differ from a regular `val`?
basics
~20 sconst val is a value the compiler knows at compile time and copies directly into the code that uses it. A plain val is set when the program runs and is read through a hidden getter method.
What is a destructuring declaration in Kotlin, and what does `val (name, age) = person` actually do under the hood?
basics
~10 sIt unpacks one object into several variables in a single line. Each variable is filled by calling the object's component functions in order: the first gets component1(), the second component2().
In Kotlin, what is the difference between == and ===? Which one calls equals()?
basics
~10 s== checks if two values are equal (same contents) by calling equals(). === checks if two variables point to the exact same object in memory. Use == for value checks.
Why can you use a variable as non-null after calling requireNotNull(x) or checkNotNull(x), even though the null check happens inside a separate function?
basics
~20 sThose standard functions tell the compiler a fact: if they return normally, the argument is not null. So after the call the compiler treats the variable as non-null and lets you use it without ?. or !!.
What does the Elvis operator ?: do in Kotlin, and what is a typical example of using it?
basics
~10 sThe Elvis operator ?: gives a fallback value when the left side is null. You write a ?: b: if a is not null you get a, otherwise you get b.
A Java method returns a value Kotlin sees as a platform type (e.g. String!). How do you safely give it a default when it is null, and what does the ?: (Elvis) operator do here?
basics
~10 sUse the Elvis operator: val name = javaCall() ?: "unknown". If the left side is null, you get the value on the right. It gives a safe default instead of risking a crash.
What does `this::myProp.isInitialized` do, and why would you use it on a `lateinit var`?
basics
~20 sIt checks whether a lateinit property has already been given a value. If you read a lateinit property before it is set, the app crashes; this check lets you ask 'is it set yet?' first and avoid the crash.
What is `lateinit var` in Kotlin, and what problem does it solve?
basics
~10 slateinit lets you declare a non-null property without giving it a value right away. You promise to set it later before using it, so you avoid making it nullable.
In Kotlin, what is `Any`, and how does it relate to `Any?`? Which one is the true root of the whole type system?
basics
~20 sAny is the parent of every non-null type. Any? adds the possibility of null, so it sits above Any and is the top of the whole type system — every value of any type is an Any?.
What is the difference between the as and as? cast operators in Kotlin, and what happens when each fails?
basics
~20 sas forces a value to a type and crashes with an error if it is not that type. as? tries the same but gives back null instead of crashing when the value does not match.
In Kotlin, what does the `out` modifier on a type parameter mean, as in `interface Source<out T>`, and how does it affect assignment between generic types?
basics
~10 sout makes the type parameter covariant: the type only produces (returns) values of T, never consumes them. So a Source<Cat> can be used where a Source<Animal> is expected, because every Cat is an Animal.
What is JVM type erasure, and what happens to the type argument of a `List<String>` at runtime in Kotlin?
basics
~10 sAt compile time the type knows it holds Strings, but at runtime the JVM forgets the generic part. A List<String> and a List<Int> are just a plain List to the running program.
The JVM erases generics at runtime, so a method that takes a List<T> cannot 'see' what T is. How do you pass the concrete type into a non-inline function so it survives to runtime, and what is the difference between Class<T> and KClass<T>?
basics
~20 sYou hand the type in by hand as a parameter, like a label. Add a Class<T> or KClass<T> argument so the function knows the real type at runtime. Class is the Java type token; KClass is the Kotlin one.
What is an abstract class in Kotlin, and how do you declare an abstract member that subclasses must implement?
basics
~10 sAn abstract class is one you cannot create objects from directly. It can have members marked abstract that have no body, and any non-abstract subclass must provide their implementation.
How do you create a class whose only way to be constructed is through a named factory function on its companion object, hiding the real constructor?
basics
~10 sMark the constructor private and add a function in the companion object that creates and returns the instance. Callers use the named function instead of calling the constructor directly.
What is a companion object in Kotlin, and how do you call its members?
basics
~10 sIt is a special object declared inside a class with the 'companion object' keywords. Its properties and functions can be called using the class name directly, without creating an instance.
What is a destructuring declaration in Kotlin, and what makes `val (a, b) = point` work under the hood?
basics
~10 sIt lets you pull several values out of one object in a single line, like val (x, y) = point. Kotlin does it by calling special functions named component1(), component2(), and so on.
What does the generated copy() function on a Kotlin data class do, and why is it useful for immutable data?
basics
~10 scopy() makes a new object that is the same as the old one, except for the properties you choose to change. The original stays untouched, so you update data without modifying it in place.
What do Kotlin's apply { } and also { } return, and how does each give you access to the object inside the lambda?
basics
~10 sBoth apply and also return the same object you called them on. Inside apply you use it as this; inside also you use it as it. Neither changes what value comes out.
What are default arguments in Kotlin, and how do they let you avoid writing multiple overloads?
basics
~10 sA default argument gives a parameter a value used when the caller omits it. So one function with defaults replaces many overloaded functions that differ only by which parameters they accept.
In Kotlin, when you call an extension function, what determines which function actually runs: the variable's declared type or the actual object stored in it?
basics
~10 sThe variable's declared type decides. Kotlin picks the extension function at compile time based on how the variable is typed, not on the real object it holds at runtime.
What is an extension function in Kotlin, and how do you declare one?
basics
~20 sAn extension function lets you add a new function to an existing type without changing its source. You write the type name before the function name, like fun String.shout(), and call it as if it were a normal method.
What is a Kotlin extension property, and how do you declare one (e.g. a `lastIndex` for `String`)?
basics
~10 sAn extension property lets you add a property to an existing type without changing its code. You write it like val String.lastIndex with a custom getter that computes the value.
What is the difference between a bound reference like `instance::method` and an unbound reference like `Type::method` in Kotlin?
basics
~10 sA bound reference already remembers which object to call the method on, so you just pass arguments. An unbound reference does not; you must pass the object itself as the first argument.
What does it mean that a Kotlin lambda 'closes over' a variable, and what can a lambda do with a captured local variable that a Java lambda cannot?
basics
~10 sA Kotlin lambda can read and remember variables from the function around it. Unlike Java, it can also change a captured var, not just read it.
What does it mean to compose two functions in Kotlin, and how would you write an `andThen` helper that runs one function and feeds its result into another?
basics
~10 sComposing means chaining functions so one's output becomes the next's input. An andThen helper takes function f, then g, and returns a new function that does g(f(x)) for any input x.
What does the crossinline modifier do on a lambda parameter of an inline function?
basics
~20 scrossinline marks a lambda of an inline function so it cannot use a non-local return. It is still inlined, but you are not allowed to write 'return' to exit the calling function from inside it.
What does the `::` operator do when written as `list.map(::println)`, and how is it different from writing `list.map { println(it) }`?
basics
~20 s::println turns an existing function into a value you can pass around. It does the same job as the lambda { println(it) }, just shorter, because you reuse a function that already exists instead of writing a new one.
Given a list of numbers, how do you compute its sum, average, and count in Kotlin, and how do you sum a numeric property of a list of objects?
basics
~10 sUse sum() to add numbers, average() for the mean, count() for how many. To sum a field of objects, use sumOf { it.field }, which adds up the chosen value for each item.
How do you create an array in Kotlin and read/write its elements?
basics
~10 sUse arrayOf(1, 2, 3) to make one, then read or change an element with square brackets like a[0] or a[0] = 9. Get the length with a.size.
What does the buildList { } function do, and what is the type of the value it returns?
basics
~10 sbuildList gives you a temporary mutable list to fill inside the braces, then hands back a normal read-only List. You add items with add(), and the final list cannot be changed afterward.
What is the Comparable interface in Kotlin, and what does implementing compareTo give you?
basics
~10 sComparable means a type has a built-in natural order. You write compareTo, which returns a negative number, zero, or positive number. Then you can sort the items and use < and > on them.
In Kotlin, what is the difference between accessing a list element with `list[i]`, `list.getOrNull(i)`, and `list.getOrElse(i) { default }`? When does each fail or succeed?
basics
~10 slist[i] throws an error if the index is out of range. getOrNull(i) returns null instead of throwing. getOrElse(i) { ... } returns a value you compute when the index is out of range.
What does the async coroutine builder return, and how do you get the result out of it?
basics
~10 sasync starts a background task and hands you a Deferred. You call await() on it to wait for and receive the result value.
When you call async { ... } and the block throws an exception, at what point is that exception observed by the caller?
basics
~10 sThe exception is stored inside the Deferred result and is re-thrown when you call await() on it. Calling async itself does not throw.
What is suspendCancellableCoroutine and when do you use it?
basics
~10 sIt is a helper that turns an old-style callback API into a suspend function. You pause the coroutine, then call resume in the callback to continue with a result, or resumeWithException to fail.
You launch a coroutine that runs a tight CPU-bound while-loop, then call cancel() on its Job. The loop keeps running. Why, and what is the simplest fix?
basics
~10 sCancellation is cooperative: the coroutine only stops if it checks for cancellation. A pure CPU loop never checks, so it ignores cancel(). Add a check inside the loop, such as while (isActive).
What is a Channel<T> in Kotlin coroutines, and how do producer and consumer coroutines communicate through it?
basics
~10 sA Channel is a pipe between coroutines. One coroutine puts values in with send, another takes them out with receive. Both suspend (wait politely) until the other side is ready.
What does the buffer() operator do to a Kotlin Flow, and why would you add it to a pipeline?
basics
~20 sbuffer() lets the part producing values and the part collecting them run at the same time instead of taking turns. Producers can race ahead into a small queue, so a slow collector no longer slows the producer.
What does flowOf(...) do, and how does it differ from a list of values?
basics
~10 sflowOf takes a fixed set of values and wraps them in a Flow, emitting each one in order when you collect it. A list just holds values; a Flow streams them on demand.
What is the flow { } builder in Kotlin, and what does it mean that the flow it creates is 'cold'?
basics
~10 sflow { } makes a stream of values. Inside the block you call emit(value) to send each item. Nothing runs until someone collects it. A cold flow re-runs its code fresh for every collector.
What is callbackFlow and when would you reach for it instead of the plain flow { } builder?
basics
~10 scallbackFlow turns an old-style callback or listener API into a Flow. You use it when values arrive through a callback you register, not from suspending code you call directly.
What does the `catch { }` operator do in a Kotlin Flow, and which exceptions can it handle?
basics
~10 scatch runs when something fails earlier in the flow (upstream). It only catches errors from the parts above it, lets you log them, and can send a backup value instead of crashing.
How do you perform bitwise operations in Kotlin, and how does this differ syntactically from Java?
basics
~20 sKotlin has no &, |, ^, <<, >> symbols. Instead it uses named infix functions like and, or, xor, shl, shr on Int and Long. So you write a and b instead of a & b.
Why can you assign to a val exactly once inside a `run { }` lambda and have the compiler accept it as definitely initialized afterwards? What language feature makes this work?
basics
~20 sThe standard-library functions like run and let promise the compiler that the lambda you pass runs exactly once. Because of that promise, the compiler knows a val you set inside the lambda gets set once, so it treats it as initialized.
After calling require(x is String) or x?.let { ... } in stdlib, the compiler often lets you treat x as the narrowed type without an extra cast. What language feature makes the standard library functions like require, check, and requireNotNull propagate type information to the caller?
basics
~10 sKotlin contracts. The stdlib functions declare a promise about how they behave, so the compiler knows that if the call returns normally, a condition is true. It then smart-casts the variable for you.
What is the exact operator function signature a class must provide so an instance of it can be used as a custom delegate for a read-only `val` property via `by`?
basics
~10 sThe delegate needs an operator function named getValue that takes the owner object and the property as parameters and returns the value. For a var you also add a setValue.
How do you get the current wall-clock instant in Kotlin's standard library, and what type does it return?
basics
~10 sUse kotlin.time.Clock.System.now(). It returns an Instant, which is a single point in time (a timestamp) — not a date or a clock you read on a wall.
What does the apply scope function do, and why is it convenient for configuring an object right after you create it?
basics
~10 sapply runs a block on an object, lets you set its properties using 'this', and returns that same object. So you can create something and configure it in one expression.
What problem does the @DslMarker annotation solve in a Kotlin type-safe builder DSL?
basics
~10 sIn a nested builder block, methods from the outer block are still callable by accident. @DslMarker hides the outer receiver inside inner blocks, so you only see the members that belong where you are.
Explain the roles of the plugins {} and dependencies {} blocks in build.gradle.kts. How do you apply a plugin and declare an implementation dependency?
basics
~10 splugins {} applies Gradle plugins that add build capabilities and tasks. dependencies {} lists the libraries your code needs, grouped by configuration like implementation or testImplementation. You add a library with implementation("group:name:version").
What is build.gradle.kts and how does it differ from a build.gradle file?
basics
~10 sbuild.gradle.kts is a Gradle build script written in Kotlin instead of Groovy. Because it is real Kotlin code, the IDE gives autocomplete, type checking, and click-through navigation that the Groovy script cannot.
In a kotlinx.html-style DSL like html { body { p { +"hi" } } }, what Kotlin language feature makes the nested blocks work, and why can each block call functions like body or p without a qualifier?
basics
~10 sEach block is a lambda that runs 'on' an object (a receiver). Inside the block you can call that object's functions directly, so body() and p() are methods of the current builder.
You have a Kotlin class with a companion object containing a function create(). How do you call that function from Java, and why isn't the call simply Foo.create()?
basics
~10 sFrom Java you call Foo.Companion.create(). Kotlin puts companion members on a nested object named Companion, so Java must go through that object rather than calling the method straight on the class.
A Kotlin file Utils.kt declares a top-level function fun greet(): String. How does Java call it, and where does that method actually live on the JVM?
basics
~10 sKotlin puts top-level functions into an auto-generated class named after the file plus 'Kt'. So Utils.kt's greet() is called from Java as UtilsKt.greet().
You write a Kotlin function fun greet(name: String, greeting: String = "Hello"). A Java colleague says they can only call it by passing both arguments. Why can't Java omit the defaulted parameter, and what is the simplest fix?
basics
~10 sKotlin default values live only in Kotlin metadata, not in the compiled method signature Java sees. So Java must pass every argument. Adding @JvmOverloads makes Kotlin also generate the shorter overloads Java can call.
When a Kotlin interface has a method with a body (a default implementation), how is that body compiled for the JVM by default, and what is the DefaultImpls class?
basics
~20 sKotlin lets interface methods have a body. By default the compiler does not put that body on the JVM interface itself; it copies it into a hidden helper class so classes implementing the interface can reuse it.
When you call a Java method that takes an int[] from Kotlin, what Kotlin type do you pass, and why not Array<Int>?
basics
~10 sUse Kotlin's IntArray for a Java int[]. Array<Int> is an array of boxed Integer objects (Integer[]), which is a different Java type and won't match an int[] parameter.
In a Kotlin Multiplatform project, what does `actual typealias UUID = java.util.UUID` do, and why would you use it instead of writing an `actual class`?
basics
~10 sIt says: on this platform, the shared expect class UUID is exactly the platform's own UUID type. You reuse an existing native type directly instead of writing a wrapper class around it.
In a Kotlin Multiplatform module, what artifact does the androidTarget() produce versus the iosArm64()/iosSimulatorArm64() targets, and how does each get consumed?
basics
~10 sandroidTarget() builds an Android library (an AAR) that Android apps use. The iOS targets build a native framework that an Xcode/Swift app imports. Same Kotlin code, two different output packages.
What is the cinterop tool in Kotlin/Native, and what role does a .def file play when binding to a C library?
basics
~10 scinterop is a Kotlin/Native tool that reads C header files and produces Kotlin code so you can call the C library from Kotlin. A .def file tells it which headers and library to use.
In a Kotlin Multiplatform project, what is the `commonMain` source set and what kind of code belongs in it?
basics
~10 scommonMain holds shared code that compiles to every target (JVM, iOS, JS, etc.). Put platform-independent logic there. It can only use APIs available on all targets.
In a Kotlin Multiplatform project, what does it mean that the standard library is available in commonMain, and which kinds of APIs can you safely call there?
basics
~20 scommonMain is shared code that compiles to every target. There you can use the common part of Kotlin's standard library — lists, maps, math, random, strings, numbers — but not platform-only things like Java's File or full Java reflection.
What is the difference between build.gradle and build.gradle.kts, and what do you gain by choosing the Kotlin DSL?
basics
~10 sbuild.gradle uses the Groovy language; build.gradle.kts uses Kotlin. The Kotlin version is type-checked, so the IDE gives autocompletion, error highlighting, and reliable refactoring before you run the build.
You're adding Room to a Kotlin module. Which Gradle dependency configuration do you use to wire up Room's annotation processor, and what else must you add to the build?
basics
~20 sYou add the Room library as a normal dependency, and put Room's compiler on the ksp configuration (the modern way) instead of a plain dependency. You also apply the KSP Gradle plugin so ksp(...) exists.
What does the Kotlin compiler's jvmTarget option control, and what happens if you target a higher bytecode version than the JDK that actually runs your app?
basics
~10 sjvmTarget sets which Java bytecode version the compiler produces, like 17 or 21. If you produce bytecode newer than the JVM running it, the app fails to start with an UnsupportedClassVersionError.
Kotlin classes are final by default. Why does that break Spring and JPA, and what compiler plugins solve it?
basics
~20 sKotlin classes can't be subclassed unless you write 'open'. Spring and Hibernate need to subclass your classes to add behavior. The all-open and no-arg plugins make the needed classes open and give them an empty constructor automatically.
What is detekt and what does running the `detekt` Gradle task do for a Kotlin project?
basics
~10 sdetekt is a static analysis tool for Kotlin. It scans your source code without running it and reports code smells, overly complex functions, and style problems so you can fix them.
Why should a class that launches coroutines take a CoroutineDispatcher as a constructor parameter instead of hardcoding Dispatchers.IO or Dispatchers.Default?
basics
~10 sSo tests can pass in a fake, controllable dispatcher. If the dispatcher is hardcoded, the test cannot speed up or control timing and must wait for real threads, making tests slow and flaky.
In kotlinx-coroutines-test, what are StandardTestDispatcher and UnconfinedTestDispatcher, and how do they differ in when they execute a newly launched coroutine?
basics
~10 sBoth are test dispatchers using fake time. StandardTestDispatcher waits: a new coroutine just gets queued until you advance time. UnconfinedTestDispatcher is eager: it runs the new coroutine immediately until its first suspension point.
What is runTest and why do you use it to test suspend functions instead of runBlocking?
basics
~10 srunTest is a helper from kotlinx-coroutines-test that runs a suspend test body. It skips delays using a fake clock, so tests with delay() finish instantly instead of really waiting.
What is virtual time in coroutine tests, and why does a delay(10_000) inside runTest finish almost instantly instead of taking 10 seconds?
basics
~10 sCoroutine tests use a fake clock. Instead of really waiting, the test scheduler just moves the clock forward, so delays complete immediately and tests stay fast and deterministic.
How do you collect all emissions from a finite Flow in a test and assert the exact sequence of values?
basics
~10 sCall toList() on the flow inside a runTest block to gather every emitted value into a List, then compare it to the expected list with assertEquals(expected, actual).
What types are allowed as parameters of a Kotlin annotation, and which types are NOT allowed?
basics
~10 sAnnotation parameters can only be simple compile-time values: numbers, Boolean, Char, String, enums, a class reference, another annotation, and arrays of those. You cannot use arbitrary objects like a List or a date.
What is a callable reference in Kotlin, and how do you write a reference to a top-level function, a member function, and a property?
basics
~10 sA callable reference points at an existing function or property by name using the :: operator, so you can pass it around instead of writing a lambda. Example: list.map(String::length).
How do you invoke a function at runtime using Kotlin reflection's KFunction.call(), and what arguments must you pass?
basics
~20 sYou get a KFunction (for example from ::myFunc or a KClass member) and call its call(...) method, passing the arguments in the same order the function declares them. For a member function, the first argument is the receiver object.
In kotlinx.serialization, what does @Contextual do and why would you need it for a type like java.util.Date?
basics
~10 s@Contextual tells the serializer: don't pick a serializer at compile time for this property. Look one up at runtime from a registered module. You use it for types you can't annotate, like java.util.Date.
In kotlinx.serialization, what is a custom KSerializer and when would you write one by hand instead of relying on the @Serializable-generated serializer?
basics
~20 sIt is a small class that tells the library exactly how to turn one type into data and back. You write one when the default behavior is wrong, for types you cannot annotate, or when the wire format must differ from your class.