Skip to content
tezvyn:

Top 30 Android & Kotlin Interview Questions and Answers

30 multiple-choice questions on Android & Kotlin, of the kind that come up in a technical interview, drawn from 30 bites in the Android & Kotlin library. Answer them here or read straight down. Every question carries the correct option, why it is correct, and a link to the bite it came from.

Jetpack Compose, Android Studio, Kotlin, Material You

30 questions. Pick an answer, or open “Show the answer” to read it.

Answers are graded in your browser. Nothing is saved, and no XP or streak is earned here. The app keeps score.

  1. Question 1 of 30

    In Kotlin, what does declaring a variable with val guarantee about the referenced object?

    Show the answer

    Answer: c · The reference cannot be reassigned, though the object's contents may still mutate

    val only prevents reassigning the reference itself, so a val holding a MutableList can still be modified. The most tempting distractor confuses reference immutability with deep object immutability, which val does not enforce.

    Read the full bite: Explain val vs var in Kotlin and null safety risks

  2. Question 2 of 30

    What is the main advantage of Kotlin's approach to null safety with default non-nullable types?

    Show the answer

    Answer: d · It shifts the detection of potential NullPointerExceptions from runtime to compile time.

    Kotlin's type system is explicitly designed to prevent NullPointerExceptions (NPEs) at compile time, a major benefit over languages that only catch them at runtime. Option B is a common misconception; val declares a read-only reference, not necessarily a compile-time constant.

    Read the full bite: Explain val, var, and null safety in Kotlin

  3. Question 3 of 30

    Given the Kotlin declaration `val userNames = mutableListOf("Alice")`, which statement accurately describes the `userNames` variable?

    Show the answer

    Answer: d · The variable `userNames` cannot be reassigned, but the list it points to can be modified.

    The `val` keyword creates a read-only reference, meaning the `userNames` variable cannot be reassigned. However, the `mutableListOf` object it points to is still mutable, allowing its contents to be changed. A common misconception is that `val` makes the object itself immutable.

    Read the full bite: Explain val vs. var and null safety in Kotlin

  4. Question 4 of 30

    If user is null, what happens when evaluating user?.name ?: "Guest"?

    Show the answer

    Answer: b · It returns Guest without throwing an exception

    The safe call operator ?. returns null when user is null, and the Elvis operator ?: then substitutes Guest as the fallback. Option C is tempting because ?. does preserve nullability, but it ignores that ?: immediately provides the default value.

    Read the full bite: What do the safe call and Elvis operators do in Kotlin?

  5. Question 5 of 30

    Given a nullable `user: User?`, how do you safely get its name's length, returning 0 if either `user` or its `name` property is null?

    Show the answer

    Answer: d · user?.name?.length ?: 0

    The safe call `?.` accesses properties only if the object is not null, and the Elvis operator `?:` provides the default value `0` if the preceding expression is null. The `if/else` block is verbose and not idiomatic Kotlin.

    Read the full bite: Purpose of Kotlin's safe call (`?.`) and Elvis (`?:`) operators?

  6. Question 6 of 30

    Given `data class User(val name: String?)` and a nullable `val activeUser: User?`, which Kotlin expression correctly retrieves the user's name, providing "Guest" if `activeUser` is null or its `name` property is null?

    Show the answer

    Answer: d · activeUser?.name ?: "Guest"

    Option D correctly uses the safe call operator (?. ) to access 'name' only if 'activeUser' is not null, and then the Elvis operator (?: ) to provide "Guest" if the result is null. Option C, while functionally correct, is considered non-idiomatic Kotlin as it uses a verbose if/else block instead of the more concise and expressive ?. and ?: operators.

    Read the full bite: Purpose of safe call (`?.`) and Elvis (`?:`) operators

  7. Question 7 of 30

    If a class has a member function and an extension function is defined with the same signature, which one will be invoked when called on an instance of that class?

    Show the answer

    Answer: b · The member function, because member functions always take precedence.

    When a member function and an extension function have the same signature, the member function will always be chosen. This is because extension functions are resolved statically and do not override class members, making the member function the more specific choice.

    Read the full bite: What is a Kotlin extension function? Write one for String.

  8. Question 8 of 30

    Which statement accurately describes the underlying mechanism of Kotlin extension functions?

    Show the answer

    Answer: c · They are compiled into static utility methods where the receiver object is passed as the first parameter.

    The card explicitly states that extension functions are "syntactic sugar for static utility methods" and are "compiled down to static methods that take the receiver object as the first argument." They do not modify the original class or its bytecode, which is a common misconception.

    Read the full bite: What is a Kotlin extension function? Write one for String.

  9. Question 9 of 30

    Which statement accurately describes how Kotlin resolves an extension function call on a receiver?

    Show the answer

    Answer: c · It uses the compile-time declared type of the receiver, compiling down to a static method call

    Kotlin extension functions are resolved at compile time based on the declared receiver type and compile to static methods, not real class members. Option D is tempting because it mirrors true polymorphic dispatch, but extensions are statically dispatched and cannot be overridden.

    Read the full bite: What is an extension function? Write a hasWhitespace extension for String.

  10. Question 10 of 30

    When working with immutable state in Kotlin, which generated function of a data class is specifically designed to create a new object instance with modified properties without altering the original?

    Show the answer

    Answer: b · copy()

    The copy() function is specifically designed to create a new instance of the data class, allowing certain properties to be modified while leaving the original object unchanged, which is crucial for immutable state management. The other generated functions serve different purposes like comparison, string representation, or hash generation, not for creating modified copies.

    Read the full bite: What are the advantages of a Kotlin data class and its functions?

  11. Question 11 of 30

    When managing immutable state with a data class, what is the primary role of the generated `copy()` function?

    Show the answer

    Answer: b · To create a new, modified instance of the object, leaving the original unchanged.

    The `copy()` function is central to working with immutable objects; it creates a new instance with specified changes, leaving the original untouched. Option A is a critical misunderstanding, as `copy()` never mutates the original object, which is key to predictable state management.

    Read the full bite: What are the advantages of a Kotlin data class?

  12. Question 12 of 30

    When using a Kotlin data class as a key in a HashMap, which statement about its compiler-generated behavior is true?

    Show the answer

    Answer: b · Only properties defined in the primary constructor marked as val or var are used in generated equals and hashCode, so the key remains consistent in the map.

    The compiler only incorporates primary constructor properties marked val or var into generated equals and hashCode, guaranteeing the contractual consistency required for safe use as a HashMap key. Option C is a tempting distractor because developers often assume body properties participate in structural equality, but the compiler intentionally excludes them.

    Read the full bite: What are the primary advantages of using a data class?

  13. Question 13 of 30

    An Android Fragment needs a property for a complex, computationally expensive object that is only used in certain user flows. The object should be created only once. Which declaration is most appropriate?

    Show the answer

    Answer: b · private val myObject: MyObject by lazy { createExpensiveObject() }

    `val by lazy` is ideal for expensive, immutable properties because it defers creation until first access and caches the result. `lateinit var` is incorrect because the property is immutable and is meant for when an external framework provides the value, not for deferred computation.

    Read the full bite: lateinit var vs. val by lazy in Android

  14. Question 14 of 30

    Which statement accurately describes a fundamental difference between lateinit var and val by lazy in Kotlin?

    Show the answer

    Answer: b · val by lazy can initialize properties of any type, including primitives, unlike lateinit var.

    The card states that lateinit var cannot be used for primitive types like Int or Boolean, while val by lazy has no such restriction. Option A is incorrect because it describes the behavior of val by lazy, not lateinit var, which is initialized manually.

    Read the full bite: lateinit var vs. val by lazy in Android

  15. Question 15 of 30

    In an Activity, a property holds a ViewModel obtained via ViewModelProvider in onCreate. Why is lateinit var more suitable than val by lazy?

    Show the answer

    Answer: c · lateinit var allows imperative assignment and can be reassigned if the Activity is recreated

    lateinit var is designed for mutable properties assigned imperatively in lifecycle callbacks like onCreate and can be reassigned when the Activity is recreated, whereas val by lazy is immutable and self-initializing. Option D is tempting but wrong because it describes lazy's first-access caching behavior, not lateinit's imperative assignment model.

    Read the full bite: Explain lateinit var versus val by lazy in Android

  16. Question 16 of 30

    What core characteristic of Kotlin's function handling makes higher-order functions possible?

    Show the answer

    Answer: b · The treatment of functions as first-class citizens, allowing them to be passed as arguments or returned.

    The card explicitly states that higher-order functions are possible "because Kotlin treats functions as first-class citizens, meaning they can be stored in variables or passed as arguments." This fundamental concept allows functions to be used as parameters or return values. While type inference is a useful Kotlin feature, it does not enable the core mechanism of functions being treated as first-class entities.

    Read the full bite: Explain and implement a Kotlin higher-order function

  17. Question 17 of 30

    In Kotlin, what is the defining characteristic that makes a function a 'higher-order function'?

    Show the answer

    Answer: b · It accepts a function as an argument or returns a function as its result.

    The correct answer is right because the definition of a higher-order function is one that treats functions as first-class citizens by taking them as parameters or returning them. While many higher-order functions operate on collections (a tempting distractor), this is a common use case, not the defining property.

    Read the full bite: Explain and implement a higher-order function in Kotlin

  18. Question 18 of 30

    What distinguishes filterAndTransform as a higher-order function rather than merely a generic function in Kotlin?

    Show the answer

    Answer: d · It takes other functions as arguments, such as predicate and transform

    A higher-order function must accept or return a function, so taking predicate and transform as arguments makes it one. Option C describes generics, which alone do not make a function higher-order.

    Read the full bite: Explain higher-order functions and implement filterAndTransform

  19. Question 19 of 30

    To model a state machine where each state might carry unique, type-specific data (e.g., a success state holding a user object, an error state holding a message), which Kotlin construct is most appropriate?

    Show the answer

    Answer: b · A sealed class

    Sealed classes are specifically designed for representing restricted hierarchies where subclasses can be distinct types (like data classes or objects) and hold different associated data. Enum classes cannot hold different types of data for each constant, making them unsuitable for states with unique payloads.

    Read the full bite: When to use a sealed class instead of an enum?

  20. Question 20 of 30

    To model a network request's state—`Loading`, `Success` (with data), or `Error` (with a message)—which Kotlin construct is most suitable?

    Show the answer

    Answer: d · A sealed class, because each of its subclasses can carry different data types specific to that state.

    A sealed class is ideal because its subclasses can represent states with different associated data (e.g., data for Success, a message for Error) in a type-safe way. An enum is a set of constants of the same type and cannot elegantly model states with different data requirements.

    Read the full bite: When would you use a sealed class instead of an enum?

  21. Question 21 of 30

    When modeling a closed set of UI states where Loading needs no data, Success carries a User, and Error carries a String, why is a sealed class preferable to an enum?

    Show the answer

    Answer: b · Enum constants share a single constructor signature, making it awkward to attach different data to each state, whereas sealed subclasses can define their own parameters

    The correct answer captures the core structural distinction: enums force all constants into one uniform signature, while sealed subclasses can each carry heterogeneous state. Option C is tempting because data classes appear to model payloads well, but without the sealed modifier the hierarchy is open, so when expressions lose compile-time exhaustiveness and external code could add unhandled states.

    Read the full bite: When would you use a sealed class instead of an enum?

  22. Question 22 of 30

    You must convert a nullable `user` into a `Session`, logging the user's ID first. Which implementation is the most idiomatic and correct for the function body?

    Show the answer

    Answer: b · return user?.let { log(it.id); Session(it) }

    `let` is ideal as it executes a block on a non-null object and returns the lambda's result, which is the new `Session` object. The `apply` function is a tempting but incorrect alternative because it would return the original `user` object, not the `Session`.

    Read the full bite: Compare and contrast Kotlin's `apply` and `let` scope functions

  23. Question 23 of 30

    Given val result = name?.apply { trim().length } where name is String?, what is the inferred type of result and why?

    Show the answer

    Answer: c · String? because apply always returns the original receiver object, ignoring the lambda's final value

    apply returns the context object itself, so the expression yields String?, not the lambda's Int result. Option B confuses apply with let, which returns the lambda's final value.

    Read the full bite: Compare Kotlin apply and let scope functions

  24. Question 24 of 30

    Which Kotlin scope function is most idiomatic for configuring an object's properties and then returning the configured object itself?

    Show the answer

    Answer: a · apply

    apply is specifically designed for object configuration; it executes a block of code on the receiver (available as 'this') and returns the receiver object itself. In contrast, let returns the result of its lambda, making it unsuitable for directly returning the configured object.

    Read the full bite: Compare and contrast `apply` and `let` scope functions

  25. Question 25 of 30

    What is the fundamental reason `reified` type parameters can only be used with `inline` functions in Kotlin?

    Show the answer

    Answer: c · inline allows the compiler to substitute the concrete type argument for the generic parameter directly into the bytecode at the call site, bypassing JVM type erasure.

    Option C correctly identifies that inline enables the compiler to replace the generic type with its concrete type at the call site, thus preserving it from JVM type erasure for runtime access. Option D is a common misconception; while inline offers performance, its necessity for reified is about enabling type information availability, not just optimizing checks.

    Read the full bite: What problem does `inline` solve, and how does `reified` relate?

  26. Question 26 of 30

    Why must a Kotlin function be declared `inline` to use a `reified` type parameter?

    Show the answer

    Answer: d · Because inlining moves the function's bytecode to the call site, where the compiler can access the concrete type argument.

    The `reified` keyword needs to know the actual type at runtime, which is normally erased by the JVM. The `inline` keyword enables this by copying the function's code to the call site, where the compiler knows the concrete type (e.g., `String`) and can substitute it directly into the bytecode. Option C is incorrect because `inline` doesn't prevent type erasure in general; it provides a clever workaround for a specific call.

    Read the full bite: Explain `inline` and `reified` in Kotlin

  27. Question 27 of 30

    Why does a reified type parameter require the enclosing function to be marked inline?

    Show the answer

    Answer: c · Because inlining copies the body to the call site so the compiler can substitute the concrete type into bytecode despite JVM erasure.

    Inlining copies the function body to each call site, letting the compiler replace the type parameter with the exact type argument in the generated bytecode and bypass JVM erasure. Distractor D is wrong because reified does not merely inject a Class reference; it performs compile-time type substitution to enable runtime type checks.

    Read the full bite: What does inline solve for higher-order functions, and what is reified?

  28. Question 28 of 30

    When running a background task that might fail, how do you defer exception handling until the result is actually needed?

    Show the answer

    Answer: d · Use `async` and wrap the call to `await()` in a `try-catch` block.

    `async` encapsulates any exception, which is re-thrown only when `await()` is called, allowing for deferred handling. In contrast, `launch` propagates exceptions immediately, so a `CoroutineExceptionHandler` would trigger right away.

    Read the full bite: Difference between launch and async in Kotlin Coroutines

  29. Question 29 of 30

    For a Kotlin Coroutine task that updates a UI element and does not require a return value, which builder is most appropriate?

    Show the answer

    Answer: d · launch

    The correct choice is launch because it is designed for 'fire-and-forget' operations, such as UI updates, where a direct result is not needed and it returns a Job. Using async for such a task would create a Deferred object whose result is never awaited, potentially leading to silently swallowed exceptions.

    Read the full bite: Explain launch vs. async in Kotlin Coroutines

  30. Question 30 of 30

    You need to fetch two pieces of data in parallel inside a ViewModel and return both results to the caller. Which choice best follows structured concurrency?

    Show the answer

    Answer: a · Use async for both calls and await each Deferred before returning

    async returns a Deferred that lets you retrieve computed values with await, which is exactly what you need when results must be returned, whereas launch is fire-and-forget. Option C is tempting but wrong because injecting a custom Job breaks the parent-child relationship required by structured concurrency.

    Read the full bite: Explain the difference between launch and async in Kotlin Coroutines

Could you explain these out loud?

That is what an interview actually tests. Tezvyn gives you questions like these with what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon