Skip to main content

Master Kotlin Interview Questions

Kotlin is quickly emerging as one of the most in-demand skills in the tech industry. Our all-inclusive guide provides essential Kotlin interview questions for junior, intermediate, and senior roles, equipping you with the knowledge you need to excel.

Kotlin at codeinterview

Your Ultimate Guide to Kotlin Interview Success

Introduction to Kotlin

Kotlin is a statically typed, cross-platform programming language developed by JetBrains. It was created by Dmitry Jemerov and Andrey Breslav and officially released in 2011. Kotlin is renowned for its simplicity, efficiency, and seamless interoperability with Java, making it a popular choice for modern Android development and enterprise applications. Its clean syntax, null safety features, and extensive standard library contribute to its growing popularity among developers, particularly in mobile development, server-side applications, and data science.

Table of Contents


Junior-Level Kotlin Interview Questions

Here are some junior-level interview questions for Kotlin:

Question 01: What are the main features of Kotlin?

Answer: Kotlin is a statically typed programming language developed by JetBrains, designed to interoperate fully with Java. It has gained popularity due to its expressive syntax, safety features, and modern design. Here are the main features of Kotlin:

  • One of Kotlin's most notable features is its null safety system, which helps to eliminate the NullPointerException by differentiating nullable and non-nullable types at compile-time.
  • Kotlin is designed to be fully interoperable with Java, allowing developers to use Kotlin code alongside Java code seamlessly.
  • Kotlin provides built-in support for coroutines, which are used for asynchronous programming.
  • Kotlin includes smart casts, which automatically handle type casting, reducing the need for explicit casts.
  • Kotlin allows developers to add new functions to existing classes without modifying their source code, known as extension functions.

Question 02: What is the purpose of the companion object in Kotlin?

Answer: The companion object in Kotlin is used to define static-like methods and properties that belong to the class rather than instances, enabling class-level functionality such as utility methods or factory functions. For example:

class MyClass {
    companion object {
        const val CONSTANT = "Some constant value"
        fun staticMethod() {
            println("This is a static-like method")
        }
    }
}

// Accessing companion object members
println(MyClass.CONSTANT) // Output: Some constant value
MyClass.staticMethod()   // Output: This is a static-like method
                   

Question 03: Explain the use of the lateinit keyword in Kotlin.

Answer: The lateinit keyword in Kotlin is used to declare a non-nullable property that will be initialized later. It allows you to avoid null checks and initialization in the constructor, typically for properties that are set up after the object is created. For example:

class User {
    lateinit var name: String
}

fun main() {
    val user = User()
    user.name = "Alice"  // Initializing the property later
    println(user.name)  // Output: Alice
}                            

Question 04: What will be the output of the following code?

fun main() {
    val list = listOf(1, 2, 3, 4, 5)
    val result = list.filter { it % 2 == 0 }.map { it * 2 }
    println(result)
}                            

Answer: The output will be [4, 8].

Question 05: What is a data class in Kotlin?

Answer: In Kotlin, a data class is a special class designed to hold data with minimal boilerplate code. Data classes automatically generate common methods like toString(), equals(), hashCode(), and copy(), based on the properties defined in the primary constructor. This feature simplifies the creation of classes whose main purpose is to store data, making code more concise and readable.

A data class is defined using the data keyword before the class name, and it must have at least one property in the primary constructor. For example, data class User(val name: String, val age: Int) creates a class where name and age are properties, and Kotlin generates the necessary methods for comparison and copying. Data classes also support destructuring declarations, allowing you to unpack data into separate variables easily.

Question 06: Find the error in below code.

fun main() {
    val name: String = null
    println(name.length)
}                                        

Answer: The variable name is declared as non-nullable, but it is assigned a null value, which causes a compilation error. It should be declared as val name: String? = null.

fun main() {
    val name: String? = null
    println(name?.length ?: "Name is null")
}                                       

Question 07: What are extension functions in Kotlin?

Answer: Extension functions in Kotlin allow you to add new methods or properties to existing classes without modifying their source code. This feature is useful for adding functionality to classes from libraries or third-party code. For example:

// Extension function to add a greeting method to the String class
fun String.greet() {
    println("Hello, $this!")
}

fun main() {
    "World".greet()  // Output: Hello, World!
}
In this example, fun String.greet() defines an extension function for the String class, allowing you to call greet() on any String object to print a greeting message.

Question 08: What is a higher-order function in Kotlin?

Answer: A higher-order function in Kotlin is a function that takes other functions as parameters or returns a function as a result. This feature enables functional programming techniques like callbacks, and transformations. For example:

// Higher-order function that takes another function as a parameter
fun operateOnNumbers(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

fun main() {
    val sum = operateOnNumbers(3, 4) { x, y -> x + y }  // Passing a lambda function
    println(sum)  // Output: 7
}
In this example, operateOnNumbers is a higher-order function that takes another function as a parameter (operation). It performs the operation on two integers and returns the result. The lambda { x, y -> x + y } is passed to operateOnNumbers to compute the sum of 3 and 4.

Question 09: What are lambdas in Kotlin?

Answer: In Kotlin, lambdas are anonymous functions that allow you to create functions without naming them. They are a key feature of Kotlin’s functional programming capabilities, enabling you to write more concise and expressive code. Lambdas can be used in various contexts, such as passing functions as arguments, defining inline functions, or creating custom collection operations.

A lambda expression in Kotlin is defined using curly braces {} and can capture variables from its surrounding context. For example, { x: Int, y: Int -> x + y } is a lambda that takes two integers and returns their sum. Lambdas are commonly used with collection functions like map, filter, and reduce, allowing you to perform operations on data in a declarative way.

Question 10: What will be the output of the following code?

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val result = numbers.fold(0) { sum, element -> sum + element }
    println(result)
}

Answer: The output will be 15.



Mid-Level Kotlin Interview Questions

Here are some mid-level interview questions for Kotlin:

Question 01: What is the difference between var and val in Kotlin?

Answer: In Kotlin, var is used for mutable variables whose values can be reassigned, while val is used for immutable variables whose values cannot be changed after initialization. For example, var age = 30; age = 35 is valid because var allows reassignment, whereas val name = "Alice"; name = "Bob" will cause a compilation error because val creates a read-only reference. Use var when you need to update a variable's value and val when the value should remain constant.For example:

var mutableVar = 10
val immutableVal = 20
mutableVar = 15 // This is allowed
immutableVal = 25 // This will cause a compilation error

Question 02: What will be the output of the following Kotlin code?

fun main() {
    val x = 10
    val y = 5
    println(x / y * y) 
}

Answer: The output will be 10. This is because integer division truncates the result.

Question 03: Explain the use of when expression in Kotlin.

Answer: The when expression in Kotlin is a powerful tool for conditional branching and is more flexible than the traditional switch statement found in other languages. Unlike switch, which handles only discrete values, when can work with a variety of conditions, including ranges, collections, and complex expressions. For example:

when (day) {
    "Monday" -> println("Start of the work week")
    "Saturday", "Sunday" -> println("Weekend")
    in 1..5 -> println("Weekday")
    else -> println("Invalid day")
}
In this example, when checks the value of day against several conditions, handling multiple cases, ranges, and a default branch with else.

Question 04: Find the error in below Kotlin code.

fun printDetails(name: String, age: Int = 30) {
    println("Name: $name, Age: $age")
}
printDetails("Alice", 25, "Extra Argument")

Answer: To fix the error, you should remove the extra argument "Extra Argument" from the function call. The corrected code is:

fun printDetails(name: String, age: Int = 30) {
    println("Name: $name, Age: $age")
}
printDetails("Alice", 25)                                        
In this corrected code, the function printDetails is called with the correct number of arguments: "Alice" for name and 25 for age.

Question 05: What is a sealed class in Kotlin?

Answer: A sealed class in Kotlin is a special kind of class used to represent a fixed set of related types. It restricts class hierarchies to a specific set of subclasses, enabling exhaustive when expressions and improving type safety. For example:

sealed class Result {
    data class Success(val data: String) : Result()
    object Error : Result()
}

fun handleResult(result: Result) {
    when (result) {
        is Result.Success -> println("Data: ${result.data}")
        is Result.Error -> println("An error occurred")
    }
}
Here, Result is a sealed class with Success and Error subclasses. The when expression covers all subclasses, ensuring complete type handling.

Question 06: Explain inline functions in Kotlin.

Answer: Inline functions in Kotlin are functions whose code is directly inserted into the call site, which improves performance by avoiding the overhead of function calls. For example:

inline fun greet(block: () -> Unit) {
    println("Before")
    block()
    println("After")
}

fun main() {
    greet { println("Hello") }  // Lambda code is inlined here
}
Here, the greet function is inline, so the lambda { println("Hello") } is inserted into greet's code, eliminating the function call overhead.

Question 07: What is the difference between HashMap and TreeMap in Kotlin?

Answer: In Kotlin, HashMap and TreeMap are two different implementations of the Map interface, each with unique features and use cases. HashMap uses a hash table to store key-value pairs, offering average constant-time complexity for operations like get and put. However, it does not guarantee any specific order for the elements.

On the other hand, TreeMap uses a red-black tree to maintain a sorted order of keys. This allows TreeMap to provide logarithmic time complexity for operations such as get and put. It also supports operations that require sorted data. If you need elements to be stored in a specific order or perform range queries, TreeMap is the better choice, while HashMap is more efficient for general-purpose storage and retrieval of data without regard to order.

Question 08: What is the purpose of the @JvmOverloads annotation in Kotlin?

Answer: The @JvmOverloads annotation generates overloads for functions or constructors with default parameters to ensure compatibility with Java. For example:

class Person(val name: String, val age: Int = 30) {
    @JvmOverloads
    constructor(name: String) : this(name, 30)
}

Question 09: What are Kotlin’s let, run, with, apply, and also functions used for?

Answer: These are scope functions for different purposes:

  • let: Executes code with the object and returns the result.
  • run: Executes code with the object and returns the result.
  • with: Executes code with the object and returns the result (object is not changed).
  • apply: Executes code with the object and returns the object itself.
  • also: Executes code with the object and returns the object itself.

Question 10: What will be the output of the following Kotlin code?

fun main() {
    val str = "Kotlin"
    val result = str.reversed()
    println(result)
}                      

Answer: The output will be "niltok" because reversed() reverses the string.



Expert-Level Kotlin Interview Questions

Here are some expert-level interview questions for Kotlin:

Question 01: Explain the concept of coroutines in Kotlin.

Answer: Coroutines in Kotlin are lightweight, asynchronous units of work that simplify managing concurrent operations. They allow you to write non-blocking, asynchronous code in a sequential style, improving readability and performance for tasks like network requests or background computations.

import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        delay(1000L)  // Non-blocking delay for 1 second
        println("World")
    }
    println("Hello")
}                            
In this example, launch creates a coroutine that runs concurrently with println("Hello"). The delay(1000L) suspends the coroutine for 1 second without blocking the main thread, resulting in "Hello" being printed before "World".

Question 02: How does Kotlin handle null safety?

Answer: Kotlin’s type system distinguishes nullable and non-nullable types. The safe call operator ?. allows calling methods on a nullable type safely. For example:

var name: String? = "Kotlin"
println(name?.length)  // Output: 6

name = null
println(name?.length)  // Output: null                                      

Question 03: What are Kotlin’s delegation patterns? How do they work?

Answer: In Kotlin, delegation allows a class to pass the implementation of an interface to another class, promoting code reuse and composition over inheritance. By using the by keyword, a delegating class can forward interface methods and properties to a delegate object, making the code more flexible and maintainable. For example:

class UserService(private val logger: Logger) : Logger by logger                                    
Here, UserService delegates the Logger interface methods to the logger instance. This approach helps avoid code duplication and supports the principle of composition over inheritance.

Question 04: What will be the output of the following Kotlin code?

fun main() {
    val x = 10
    val y = 5
    val result = x.let { it * 2 }.takeIf { it > 10 }?.let { it / y }
    println(result)
}

Answer: The output will be 4, as x.let { it * 2 } evaluates to 20, takeIf { it > 10 } keeps 20, and let { it / y } results in 4.

Question 05: What is the purpose of operator overloading in Kotlin?

Answer: Operator overloading in Kotlin allows you to define custom behavior for standard operators like +, -, and * in your own classes. By implementing functions such as operator fun plus(other: T), you can customize how these operators work with your class instances, making the code more intuitive and expressive. For example: For example:

data class Point(val x: Int, val y: Int) {
    operator fun plus(other: Point) = Point(x + other.x, y + other.y)
}

val p1 = Point(1, 2)
val p2 = Point(3, 4)
println(p1 + p2)  // Output: Point(x=4, y=6)

Question 06: Discuss the compareAndSet method in Kotlin and its impact on performance.

Answer: compareAndSet is an atomic operation used in concurrent programming to ensure a variable’s value changes only if it matches the expected value. It improves performance by avoiding locking mechanisms. For example:

val atomicValue = AtomicInteger(0)
atomicValue.compareAndSet(0, 1)  // Atomically sets value to 1 if current value is 0

Question 07: Explain the concept of type safe builders in Kotlin.

Answer: Type-safe builders in Kotlin enable the creation of complex objects using a fluent, DSL-like (Domain-Specific Language) syntax that ensures compile-time safety and readability. These builders leverage Kotlin's powerful features to provide a clean and expressive way to construct complex hierarchies or configurations.

fun html(init: HTML.() -> Unit): HTML {
    val html = HTML()
    html.init()
    return html}

class HTML {
    fun body(init: BODY.() -> Unit) { /* ... */ }
}

class BODY
html {
    body {
        // Configure body    }
}                                                            

Question 08: What is the @Inject annotation in Kotlin used for?

Answer: The @Inject annotation in Kotlin is used for dependency injection in frameworks like Dagger and Hilt. It marks constructors, fields, or methods to be automatically provided with dependencies. This annotation simplifies dependency management and promotes loose coupling in applications. For example:

class Car @Inject constructor(private val engine: Engine) {
    // Engine is provided by the DI framework
}                                                       
Here, @Inject tells the DI framework to provide an Engine instance when creating a Car object.

Question 09: How do you handle TimeoutException in Kotlin Coroutines?

Answer: In Kotlin Coroutines, TimeoutException is managed using withTimeout or withTimeoutOrNull. The withTimeout function specifies a timeout period and throws a TimeoutCancellationException if the coroutine takes too long, which you can catch and handle, while withTimeoutOrNull returns null instead of throwing an exception if the timeout occurs. For example:

import kotlinx.coroutines.*

suspend fun fetchData(): String? {
    return withTimeoutOrNull(5000) {  // 5000 ms timeout
        delay(6000)  // Simulate long task
        "Data"
    }
}
fun main() = runBlocking {
    val result = fetchData()
    if (result != null) {
        println(result)
    } else {
        println("Operation timed out.")    }
}
Here, withTimeoutOrNull returns null if the coroutine exceeds the timeout, allowing you to handle the timeout scenario without using exceptions.

Question 10: What is the Nothing type in Kotlin, and when is it used?

Answer: In Kotlin, the Nothing type represents a value that never occurs, used for functions or expressions that either throw an exception or run indefinitely. It signifies that a function does not complete normally and is a subtype of all other types, making it useful for indicating unreachable code, signaling errors, or modeling infinite loops. For example:

fun fail(message: String): Nothing {
    throw IllegalArgumentException(message)  // Never returns
}                                  
Here, fail throws an exception, so it has a return type of Nothing.



Ace Your Kotlin Interview: Proven Strategies and Best Practices

To excel in a Kotlin technical interview, it's crucial to have a strong grasp of the language's core concepts. This includes a deep understanding of syntax and semantics, data types, and control structures. Additionally, mastering Kotlin's approach to error handling is essential for writing robust and reliable code. Understanding concurrency and parallelism can set you apart, as these skills are highly valued in many programming languages.

  • Core Language Concepts: Syntax, semantics, data types (built-in and composite), control structures, and error handling.
  • Concurrency and Parallelism: Creating and managing threads, using communication mechanisms like channels and locks, and understanding synchronization primitives.
  • Standard Library and Packages: Familiarity with the language's standard library and commonly used packages, covering basic to advanced functionality.
  • Practical Experience: Building and contributing to projects, solving real-world problems, and showcasing hands-on experience with the language.
  • Testing and Debugging: Writing unit, integration, and performance tests, and using debugging tools and techniques specific to the language.
Practical experience is invaluable when preparing for a technical interview. Building and contributing to projects, whether personal, open-source, or professional, helps solidify your understanding and showcases your ability to apply theoretical knowledge to real-world problems. Additionally, demonstrating your ability to effectively test and debug your applications can highlight your commitment to code quality and robustness.

Get started with CodeInterview now

No credit card required, get started with a free trial or choose one of our premium plans for hiring at scale.