Skip to content

Kotlin Fundamentals Interview Questions for Android App Development

25 Kotlin Fundamentals questions with answers for android app development roles — 12 easy, 10 medium, 3 hard.

About Kotlin Fundamentals

Kotlin is the official and preferred language for Android. This topic covers null safety, data and sealed classes, extension functions, scope functions, collections, generics and delegation. Interviewers use these questions to check whether you write idiomatic, safe Kotlin rather than Java-style code, so expect both theory and small coding tasks.

Sheet progressStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

What is the difference between val and var in Kotlin?

Save to ▾
Show answer
val declares a read-only reference that cannot be reassigned after initialisation, while var declares a mutable reference. Note that val does not make the object immutable: a val pointing to a MutableList can still have items added. Prefer val by default because it makes code easier to reason about and safer in concurrent code, and switch to var only when reassignment is genuinely needed.
02

How does Kotlin handle null safety?

Save to ▾
Show answer
Kotlin's type system separates nullable types (String?) from non-nullable types (String). The compiler stops you calling methods on a nullable value without a check. You use the safe call operator ?., the Elvis operator ?: for defaults, smart casts after null checks, or !! to force a value and risk a NullPointerException. This moves most null crashes from runtime to compile time, which is a major reason Android adopted Kotlin.
03

What is a data class and what does the compiler generate for it?

Save to ▾
Show answer
A data class is a class meant to hold data, declared with the data keyword and at least one property in the primary constructor. The compiler generates equals(), hashCode(), toString(), copy() and componentN() functions for destructuring, all based on primary constructor properties. They are ideal for UI state, API models and Room entities. Properties declared in the class body are not included in the generated equals or toString.
04

Write a sealed interface for a screen state and handle it with when.

Save to ▾
Show answer
sealed interface UiState { data object Loading : UiState data class Success(val items: List<String>) : UiState data class Error(val message: String) : UiState } fun render(state: UiState) = when (state) { UiState.Loading -> showProgress() is UiState.Success -> showList(state.items) is UiState.Error -> showError(state.message) }
05

What is the difference between == and === in Kotlin?

Save to ▾
Show answer
== checks structural equality and calls equals() under the hood, handling nulls safely. === checks referential equality, meaning both references point to the same object in memory. For two data class instances with the same values, == returns true but === returns false unless they are the same instance. For primitive-like types such as Int, === may behave unexpectedly due to boxing, so == is the normal choice.
06

What are higher-order functions and lambdas in Kotlin?

Save to ▾
Show answer
A higher-order function takes a function as a parameter or returns one. A lambda is an anonymous function literal like { x: Int -> x * 2 }. Collection operations such as map, filter and forEach are higher-order functions. In Android you see them in click listeners, Compose callbacks like onClick = { } and coroutine builders. If the last parameter is a function, the lambda can be written outside the parentheses, known as trailing lambda syntax.
07

Write a Kotlin function that groups a list of orders by city and returns total amount per city.

Save to ▾
Show answer
data class Order(val city: String, val amount: Double) fun totalsByCity(orders: List<Order>): Map<String, Double> = orders.groupBy { it.city } .mapValues { (_, list) -> list.sumOf { it.amount } } // Alternative with one pass: // orders.groupingBy { it.city }.fold(0.0) { acc, o -> acc + o.amount }
08

How do default and named arguments reduce the need for overloads?

Save to ▾
Show answer
Kotlin functions can define default values, such as fun showToast(msg: String, long: Boolean = false), so callers skip arguments they do not need. Named arguments, like showToast(msg = "Saved", long = true), make calls readable and let you change argument order. Together they replace telescoping constructors and builder patterns in many cases. For Java callers, add @JvmOverloads so overloads are generated automatically.
09

A teammate uses !! everywhere to silence compiler errors. How do you handle this in code review?

Save to ▾
Show answer
Explain calmly that !! converts a compile-time check into a possible runtime crash. Suggest alternatives per case: safe calls with ?.let, Elvis with a default or early return, requireNotNull with a clear message, or fixing the type at the source so it is non-null. Add a detekt rule to flag !! in new code. Pair with them on one file so the change feels like help, not criticism.
10

Write a function that safely parses a string to an Int and returns a default on failure.

Save to ▾
Show answer
fun String?.toIntOrDefault(default: Int = 0): Int = this?.trim()?.toIntOrNull() ?: default // Usage val qty = input.text.toString().toIntOrDefault(1) val age = null.toIntOrDefault() // 0
11

Tell me about a time you learned a new language or framework quickly for a project.

Save to ▾
Show answer
Situation: my team switched a feature to Kotlin when I only knew Java. Task: deliver a profile screen in two weeks. Action: I spent the first evenings on the official Kotlin koans, converted small utility classes first, and asked a senior to review my early pull requests for idiomatic usage. Result: the screen shipped on time, and my later code needed far fewer review comments. I now learn by building something small immediately.
12

Why should we hire you as a fresher Android developer?

Save to ▾
Show answer
Give evidence, not adjectives. For example: I have built and published two apps using Kotlin and Jetpack Compose, one with Room and Retrofit and an MVVM structure, and both are on my GitHub with a README and tests. I debug by reading logs and stack traces before asking for help, and I am comfortable learning from code reviews. I can contribute to bug fixes and small features from the first month.
13

Explain the difference between let, run, with, apply and also.

Save to ▾
Show answer
All are scope functions that run a block on an object. let and also receive the object as it; run, with and apply receive it as this. let, run and with return the lambda result, while apply and also return the object itself. Typical use: let for null checks (user?.let { }), apply for configuring an object, also for side effects like logging, and run or with for computing a result from an object.
14

What is a sealed class and when would you use it on Android?

Save to ▾
Show answer
A sealed class restricts its subclasses to a known set defined in the same package and module. The compiler knows every subtype, so a when expression over it can be exhaustive without an else branch. On Android it is commonly used to model UI state such as Loading, Success(data) and Error(message), or one-time events. Adding a new subtype causes compile errors wherever handling is missing, which prevents forgotten cases.
15

What are extension functions and how are they resolved?

Save to ▾
Show answer
Extension functions let you add functions to an existing class without inheriting from it, for example fun String.isValidEmail(): Boolean. They are resolved statically at compile time based on the declared type of the variable, not the runtime type, so they do not support polymorphism. They cannot access private members of the class. They are used widely in Android KTX libraries, such as Context.toast or View.isVisible.
16

What is the difference between lateinit and by lazy?

Save to ▾
Show answer
lateinit works only with var and non-primitive, non-null types; you promise to assign it before use, and accessing it early throws UninitializedPropertyAccessException. by lazy works with val; the initialiser runs once on first access and the result is cached, thread-safe by default. Use lateinit for values injected or set in lifecycle callbacks, such as a binding in onCreate, and lazy for expensive values computed on demand.
17

Explain object, companion object and object expressions.

Save to ▾
Show answer
An object declaration creates a thread-safe singleton initialised lazily on first access. A companion object is an object tied to a class, used for factory methods and constants, similar to static members in Java; add @JvmStatic for Java callers. An object expression creates an anonymous object on the spot, often to implement an interface such as a callback. Avoid holding Context or Activity references in singletons to prevent memory leaks.
18

What is the difference between List and MutableList, and is List truly immutable?

Save to ▾
Show answer
List is a read-only interface exposing only reading operations, while MutableList adds add, remove and set. A List is not guaranteed immutable: the underlying object might be an ArrayList that another reference can still modify. For real immutability use kotlinx.collections.immutable or create defensive copies. In ViewModels, expose List or StateFlow<List> publicly and keep the mutable version private to protect state.
19

What are sequences in Kotlin and when are they better than collections?

Save to ▾
Show answer
Sequences evaluate lazily, element by element, while collection operations like map and filter create a new intermediate list at every step. For long chains on large data, or when you only need the first few results with take or first, asSequence() avoids extra allocations. For small lists, plain collections are often faster because sequences add per-element overhead. Measure before switching in performance-critical code.
20

Your team is migrating a Java Android app to Kotlin. How would you plan it?

Save to ▾
Show answer
Kotlin and Java interoperate, so migrate gradually rather than all at once. Start with new features in Kotlin, then convert leaf classes like models and utilities, writing tests before converting. Add nullability annotations to Java code so Kotlin sees correct types. Review auto-converted code because it often overuses !!. Track progress per module and agree on style rules with ktlint or detekt so the codebase stays consistent.
21

A crash report shows a NullPointerException in Kotlin code. How can that happen if Kotlin is null safe?

Save to ▾
Show answer
Common causes are the !! operator, platform types from Java code without nullability annotations, accessing a lateinit property before assignment, calling a function from a constructor before properties are initialised, and reflection-based libraries like Gson setting non-null fields to null. Fix it by removing !!, adding annotations or explicit nullable types at the Java boundary, and using a Kotlin-aware serializer such as kotlinx.serialization or Moshi with Kotlin codegen.
22

Write a delegated property that logs whenever a value changes.

Save to ▾
Show answer
import kotlin.properties.Delegates class Settings { var theme: String by Delegates.observable("light") { prop, old, new -> println("${prop.name} changed from $old to $new") } } // Use Delegates.vetoable if you need to reject a change // by returning false from the lambda.
23

What does the inline keyword do and when should you use reified?

Save to ▾
Show answer
inline tells the compiler to copy the function body and lambda bodies into the call site, avoiding the object allocation for lambdas and enabling non-local returns. It suits small higher-order functions called often. reified can only be used in inline functions and keeps the generic type available at runtime, so you can write inline fun <reified T> Gson.fromJson(json: String) and use T::class. Avoid inlining large functions since it increases bytecode size.
24

Explain generics variance with in and out in Kotlin.

Save to ▾
Show answer
out marks a type parameter as covariant: the class only produces T, so List<String> can be used as List<out Any>. in marks it contravariant: the class only consumes T, like Comparator<in T>. This is declaration-site variance, replacing Java wildcards such as ? extends and ? super. Use-site projections like Array<out Number> are also possible. Getting variance right lets APIs accept more types safely without unchecked casts.
25

What are value classes and why use them?

Save to ▾
Show answer
A value class, declared with @JvmInline value class UserId(val value: String), wraps a single value to give it a distinct type without the runtime cost of an object in most cases, because the compiler unboxes it. It prevents mistakes like passing an OrderId where a UserId is expected. It may get boxed when used as a nullable type, in generics or through interfaces, so the zero-cost benefit is not guaranteed everywhere.

Frequently asked questions

How important is Kotlin Fundamentals in Android App Development interviews?

Kotlin is the official and preferred language for Android. This topic covers null safety, data and sealed classes, extension functions, scope functions, collections, generics and delegation. Interviewers use these questions to check whether you write idiomatic, safe Kotlin rather than Java-style code, so expect both theory and small coding tasks.

How should I use the Kotlin Fundamentals sheet?

Go top to bottom — easy to hard. Answer before opening each answer, tick what you solved and save misses to Last-Minute Revision.