Frequently asked top Kotlin Interview Questions and Answers with detailed example programs and references are provided here. Links would be referenced at appropriate junctures in the answers. You may refer those in case you need any clarification. Sequential reading of questions and answers is suggested, as it simulates a kind of interactive session.
What is Kotlin and why was it created?
Kotlin is a modern, statically-typed programming language that runs on the Java Virtual Machine (JVM) and can also be compiled to JavaScript or native code. It was created by JetBrains to address some of the limitations of Java, offering improved syntax, null safety, and interoperability with Java, making it a preferred choice for Android development and other JVM-based applications.
What are the main features of Kotlin?
Kotlin offers several key features, including:
- Null Safety to eliminate NullPointerExceptions.
- Concise Syntax reducing boilerplate code.
- Extension Functions to extend existing classes.
- Coroutines for asynchronous programming.
- Interoperability with Java allowing seamless integration.
- Smart Casts for automatic type casting.
- Data Classes for easy creation of classes to hold data.
Explain the differences between Kotlin and Java.
While Kotlin and Java are both JVM languages, Kotlin introduces several improvements over Java:
- Null Safety: Kotlin’s type system distinguishes between nullable and non-nullable types.
- Conciseness: Kotlin reduces boilerplate code with features like data classes and type inference.
- Extension Functions: Allows adding new functions to existing classes without inheritance.
- Coroutines: Simplifies asynchronous programming.
- Smart Casts: Automatically casts types after checking.
- Interoperability: Seamlessly works with existing Java code and libraries.
- Default and Named Arguments: Enhances function flexibility.
What is null safety in Kotlin?
Null safety in Kotlin is a feature that helps prevent NullPointerExceptions by distinguishing between nullable and non-nullable types. By default, variables cannot hold null values. To allow a variable to be null, you must explicitly declare it with a nullable type using a question mark (e.g., String?
). This enforces null checks at compile-time, ensuring safer and more reliable code.
What are data classes in Kotlin?
Data classes in Kotlin are classes primarily used to hold data. They automatically generate useful methods such as equals()
, hashCode()
, toString()
, and copy()
, reducing boilerplate code. To create a data class, use the data
keyword before the class declaration:
data class User(val name: String, val age: Int)
Explain extension functions in Kotlin.
Extension functions in Kotlin allow you to add new functions to existing classes without inheriting from them or using design patterns like Decorator. This is achieved by prefixing the function name with the class you want to extend. For example:
fun String.addHello(): String {
return "Hello, $this"
}
val greeting = "World".addHello() // "Hello, World"
What are higher-order functions in Kotlin?
Higher-order functions in Kotlin are functions that take other functions as parameters or return functions. They enable more abstract and reusable code patterns. For example, the filter
function takes a predicate function as a parameter:
val numbers = listOf(1, 2, 3, 4, 5)
val evenNumbers = numbers.filter { it % 2 == 0 } // [2, 4]
What is a lambda expression in Kotlin?
A lambda expression in Kotlin is an anonymous function that can be treated as a value – it can be passed as an argument to a function, returned from a function, or stored in a variable. Lambdas are defined within curly braces and can take parameters. For example:
val sum: (Int, Int) -> Int = { a, b -> a + b }
println(sum(3, 4)) // Outputs 7
Explain the difference between var and val in Kotlin.
var
and val
are used to declare variables in Kotlin. var
is used for mutable variables, meaning their values can be changed after initialization. val
is used for immutable variables, meaning once a value is assigned, it cannot be altered.
var mutableVar = 5
mutableVar = 10 // Allowed
val immutableVal = 5
immutableVal = 10 // Compilation error
What are sealed classes in Kotlin?
Sealed classes in Kotlin are used to represent restricted class hierarchies, where a value can have one of the types from a limited set. They are abstract by nature and cannot be instantiated directly. Sealed classes are useful in when expressions, ensuring that all possible subclasses are covered, thereby enhancing type safety.
sealed class Result
data class Success(val data: String) : Result()
data class Error(val exception: Exception) : Result()
fun handleResult(result: Result) {
when(result) {
is Success -> println(result.data)
is Error -> println(result.exception.message)
}
}
What is the companion object in Kotlin?
A companion object in Kotlin is an object that is declared within a class using the companion object
keyword. It allows you to define members that belong to the class rather than to any specific instance, similar to static members in Java. Companion objects can also implement interfaces and can be used as factory methods.
class MyClass {
companion object {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create()
Explain delegation in Kotlin.
Delegation in Kotlin is a design pattern where an object handles a request by delegating it to a second object (the delegate). Kotlin supports delegation natively through the by
keyword. This can be used for class delegation and property delegation. For example, class delegation allows a class to delegate the implementation of an interface to another object.
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { println(x) }
}
class Derived(b: Base) : Base by b
val b = BaseImpl(10)
val derived = Derived(b)
derived.print() // Outputs: 10
What is a coroutine in Kotlin?
A coroutine in Kotlin is a concurrency design pattern that allows for asynchronous programming without the complexity of traditional multi-threading. Coroutines enable writing non-blocking code by suspending and resuming execution at specific points, making it easier to handle tasks like network requests, file I/O, and other asynchronous operations in a sequential manner.
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
How does Kotlin handle inheritance?
In Kotlin, all classes are final by default, meaning they cannot be inherited unless explicitly marked as open
or abstract. To allow a class to be subclassed, you declare it with the open
keyword. Similarly, methods and properties must also be marked as open
to be overridden in subclasses.
open class Parent {
open fun greet() {
println("Hello from Parent")
}
}
class Child : Parent() {
override fun greet() {
println("Hello from Child")
}
}
What are object declarations in Kotlin?
Object declarations in Kotlin are used to create singleton instances. They are declared using the object
keyword and can contain properties, methods, and even implement interfaces. Object declarations are initialized lazily when they are first accessed.
object Database {
val name = "MyDatabase"
fun connect() {
println("Connecting to $name")
}
}
fun main() {
Database.connect()
}
Explain smart casts in Kotlin.
Smart casts in Kotlin automatically cast a variable to a target type after checking its type using is
checks. This eliminates the need for explicit casting. For example:
fun demo(x: Any) {
if (x is String) {
println(x.length) // Smart cast to String
}
}
What are inline functions in Kotlin?
Inline functions in Kotlin are functions that are expanded at the call site, which can help reduce the overhead of higher-order functions by avoiding additional function calls and object allocations. They are declared with the inline
keyword. Inline functions are particularly useful when passing lambda expressions as parameters.
inline fun performOperation(operation: () -> Unit) {
operation()
}
fun main() {
performOperation { println("Operation performed") }
}
What is the difference between checked and unchecked exceptions in Kotlin?
Kotlin does not distinguish between checked and unchecked exceptions. All exceptions in Kotlin are unchecked, meaning the compiler does not enforce exception handling or declaration. This differs from Java, where checked exceptions must be either caught or declared in the method signature.
How does Kotlin support functional programming?
Kotlin supports functional programming by providing features such as higher-order functions, lambda expressions, immutable data structures, inline functions, and extension functions. These features allow developers to write more declarative and concise code, leveraging functional programming paradigms alongside object-oriented principles.
What is the use of the ‘when’ expression in Kotlin?
The when
expression in Kotlin is a powerful control flow construct that replaces the traditional switch statement found in other languages. It allows for more flexible and expressive conditional branching by supporting arbitrary expressions, ranges, and type checks. Additionally, when
can be used as an expression, returning a value.
fun getDescription(obj: Any): String {
return when (obj) {
is Int -> "Integer"
is String -> "String"
in 1..10 -> "Between 1 and 10"
else -> "Unknown"
}
}
Explain the concept of typealiases in Kotlin.
Typealiases in Kotlin allow you to provide alternative names for existing types, making complex type declarations more readable and easier to manage. They do not create new types but simply provide a shorthand for existing ones.
typealias UserMap = Map<Int, String>
fun printUsers(users: UserMap) {
users.forEach { (id, name) ->
println("User $id: $name")
}
}
What are reified type parameters in Kotlin?
Reified type parameters in Kotlin allow you to access the actual type arguments at runtime within inline functions. This is useful for operations like type checks and reflection, which require type information. To use reified type parameters, the function must be marked with the inline
keyword and the type parameter with reified
.
inline fun <reified T> Gson.fromJson(json: String): T {
return this.fromJson(json, T::class.java)
}
val user: User = gson.fromJson<User>("{"name":"John"}")
What is the difference between open and abstract classes in Kotlin?
In Kotlin, both open
and abstract
classes can be inherited, but there are key differences:
- Open Classes: Can be inherited but can also be instantiated. They may contain both abstract and concrete members.
- Abstract Classes: Cannot be instantiated and must be inherited. They can contain abstract members that must be implemented by subclasses.
How do you handle JSON serialization/deserialization in Kotlin?
JSON serialization and deserialization in Kotlin can be handled using libraries like Gson, Moshi, or Kotlinx Serialization. These libraries provide annotations and functions to convert Kotlin objects to JSON and vice versa. For example, using Kotlinx Serialization:
import kotlinx.serialization.*
import kotlinx.serialization.json.*
@Serializable
data class User(val name: String, val age: Int)
fun main() {
val json = Json.encodeToString(User("Alice", 30))
println(json) // {"name":"Alice","age":30}
val user = Json.decodeFromString<User>(json)
println(user) // User(name=Alice, age=30)
}
import kotlinx.serialization.*
import kotlinx.serialization.json.*
@Serializable
data class User(val name: String, val age: Int)
fun main() {
val json = Json.encodeToString(User("Alice", 30))
println(json) // {"name":"Alice","age":30}
val user = Json.decodeFromString(json)
println(user) // User(name=Alice, age=30)
}
What are generics in Kotlin?
Generics in Kotlin allow you to create classes, interfaces, and functions that can operate on types specified as parameters. They enable type-safe code reuse by allowing you to define components that can work with any data type while maintaining compile-time type checking.
fun <T> List<T>.secondOrNull(): T? {
return if (this.size >= 2) this[1] else null
}
val numbers = listOf(1, 2, 3)
println(numbers.secondOrNull()) // 2
Explain the difference between public, private, protected, and internal in Kotlin.
Kotlin provides four visibility modifiers:
- public: Visible everywhere (default).
- private: Visible only within the class or file.
- protected: Visible within the class and its subclasses.
- internal: Visible within the same module.
These modifiers help in encapsulating and controlling access to class members, enhancing code safety and maintainability.
How does Kotlin support operator overloading?
Kotlin allows operator overloading by providing a set of predefined conventions for function names. You can define operator functions using the operator
modifier, enabling you to use standard operators like +
, -
, *
, etc., with custom classes.
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
}
fun main() {
val p1 = Point(1, 2)
val p2 = Point(3, 4)
val p3 = p1 + p2
println(p3) // Point(x=4, y=6)
}
What are inline classes in Kotlin?
Inline classes in Kotlin are a way to create type-safe wrappers around values without the runtime overhead of additional objects. They are declared using the value class
keyword. Inline classes help in optimizing performance by eliminating object allocations where possible.
@JvmInline
value class Email(val address: String)
fun sendEmail(email: Email) {
println("Sending email to ${email.address}")
}
fun main() {
val email = Email("example@example.com")
sendEmail(email)
}
How does Kotlin’s type inference work?
Kotlin’s type inference allows the compiler to automatically determine the type of a variable based on the initializer expression. This reduces the need for explicit type declarations, making the code more concise. However, for clarity or when the type cannot be inferred, you can still specify the type explicitly.
val number = 10 // Int inferred
val text = "Hello" // String inferred
fun add(a: Int, b: Int) = a + b // Function returns Int
How does Kotlin support operator overloading?
Kotlin allows operator overloading by providing a set of predefined conventions for function names. You can define operator functions using the operator
modifier, enabling you to use standard operators like +
, -
, *
, etc., with custom classes.
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
}
fun main() {
val p1 = Point(1, 2)
val p2 = Point(3, 4)
val p3 = p1 + p2
println(p3) // Point(x=4, y=6)
}
What are inline classes in Kotlin?
Inline classes in Kotlin are a way to create type-safe wrappers around values without the runtime overhead of additional objects. They are declared using the value class
keyword. Inline classes help in optimizing performance by eliminating object allocations where possible.
@JvmInline
value class Email(val address: String)
fun sendEmail(email: Email) {
println("Sending email to ${email.address}")
}
fun main() {
val email = Email("example@example.com")
sendEmail(email)
}
How does Kotlin handle inheritance?
In Kotlin, all classes are final by default, meaning they cannot be inherited unless explicitly marked as open
or abstract. To allow a class to be subclassed, you declare it with the open
keyword. Similarly, methods and properties must also be marked as open
to be overridden in subclasses.
open class Parent {
open fun greet() {
println("Hello from Parent")
}
}
class Child : Parent() {
override fun greet() {
println("Hello from Child")
}
}
What are object declarations in Kotlin?
Object declarations in Kotlin are used to create singleton instances. They are declared using the object
keyword and can contain properties, methods, and even implement interfaces. Object declarations are initialized lazily when they are first accessed.
object Database {
val name = "MyDatabase"
fun connect() {
println("Connecting to $name")
}
}
fun main() {
Database.connect()
}
Explain smart casts in Kotlin.
Smart casts in Kotlin automatically cast a variable to a target type after checking its type using is
checks. This eliminates the need for explicit casting. For example:
fun demo(x: Any) {
if (x is String) {
println(x.length) // Smart cast to String
}
}
What are inline functions in Kotlin?
Inline functions in Kotlin are functions that are expanded at the call site, which can help reduce the overhead of higher-order functions by avoiding additional function calls and object allocations. They are declared with the inline
keyword. Inline functions are particularly useful when passing lambda expressions as parameters.
inline fun <T> List<T>.forEachInline(action: (T) -> Unit) {
for (element in this) action(element)
}
fun main() {
listOf(1, 2, 3).forEachInline { println(it) }
}
What is the difference between open and abstract classes in Kotlin?
In Kotlin, both open
and abstract
classes can be inherited, but there are key differences:
- Open Classes: Can be inherited but can also be instantiated. They may contain both abstract and concrete members.
- Abstract Classes: Cannot be instantiated and must be inherited. They can contain abstract members that must be implemented by subclasses.
How do you handle JSON serialization/deserialization in Kotlin?
JSON serialization and deserialization in Kotlin can be handled using libraries like Gson, Moshi, or Kotlinx Serialization. These libraries provide annotations and functions to convert Kotlin objects to JSON and vice versa. For example, using Kotlinx Serialization:
import kotlinx.serialization.*
import kotlinx.serialization.json.*
@Serializable
data class User(val name: String, val age: Int)
fun main() {
val json = Json.encodeToString(User("Alice", 30))
println(json) // {"name":"Alice","age":30}
val user = Json.decodeFromString<User>(json)
println(user) // User(name=Alice, age=30)
}
What are generics in Kotlin?
Generics in Kotlin allow you to create classes, interfaces, and functions that can operate on types specified as parameters. They enable type-safe code reuse by allowing you to define components that can work with any data type while maintaining compile-time type checking.
fun <T> List<T>.secondOrNull(): T? {
return if (this.size >= 2) this[1] else null
}
val numbers = listOf(1, 2, 3)
println(numbers.secondOrNull()) // 2
Explain the difference between public, private, protected, and internal in Kotlin.
Kotlin provides four visibility modifiers:
- public: Visible everywhere (default).
- private: Visible only within the class or file.
- protected: Visible within the class and its subclasses.
- internal: Visible within the same module.
These modifiers help in encapsulating and controlling access to class members, enhancing code safety and maintainability.
How does Kotlin support operator overloading?
Kotlin allows operator overloading by providing a set of predefined conventions for function names. You can define operator functions using the operator
modifier, enabling you to use standard operators like +
, -
, *
, etc., with custom classes.
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
}
fun main() {
val p1 = Point(1, 2)
val p2 = Point(3, 4)
val p3 = p1 + p2
println(p3) // Point(x=4, y=6)
}
What are inline classes in Kotlin?
Inline classes in Kotlin are a way to create type-safe wrappers around values without the runtime overhead of additional objects. They are declared using the value class
keyword. Inline classes help in optimizing performance by eliminating object allocations where possible.
@JvmInline
value class Email(val address: String)
fun sendEmail(email: Email) {
println("Sending email to ${email.address}")
}
fun main() {
val email = Email("example@example.com")
sendEmail(email)
}
How does Kotlin’s type inference work?
Kotlin’s type inference allows the compiler to automatically determine the type of a variable based on the initializer expression. This reduces the need for explicit type declarations, making the code more concise. However, for clarity or when the type cannot be inferred, you can still specify the type explicitly.
val number = 10 // Int inferred
val text = "Hello" // String inferred
fun add(a: Int, b: Int) = a + b // Function returns Int
What are smart casts in Kotlin?
Smart casts in Kotlin automatically cast a variable to a target type after checking its type using is
checks. This eliminates the need for explicit casting. For example:
fun demo(x: Any) {
if (x is String) {
println(x.length) // Smart cast to String
}
}
What is the difference between open and abstract classes in Kotlin?
In Kotlin, both open
and abstract
classes can be inherited, but there are key differences:
- Open Classes: Can be inherited but can also be instantiated. They may contain both abstract and concrete members.
- Abstract Classes: Cannot be instantiated and must be inherited. They can contain abstract members that must be implemented by subclasses.
What is a companion object in Kotlin?
A companion object in Kotlin is an object that is declared within a class using the companion object
keyword. It allows you to define members that belong to the class rather than to any specific instance, similar to static members in Java. Companion objects can also implement interfaces and can be used as factory methods.
class MyClass {
companion object {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create()
Explain delegation in Kotlin.
Delegation in Kotlin is a design pattern where an object handles a request by delegating it to a second object (the delegate). Kotlin supports delegation natively through the by
keyword. This can be used for class delegation and property delegation. For example, class delegation allows a class to delegate the implementation of an interface to another object.
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { println(x) }
}
class Derived(b: Base) : Base by b
val b = BaseImpl(10)
val derived = Derived(b)
derived.print() // Outputs: 10
What is a coroutine in Kotlin?
A coroutine in Kotlin is a concurrency design pattern that allows for asynchronous programming without the complexity of traditional multi-threading. Coroutines enable writing non-blocking code by suspending and resuming execution at specific points, making it easier to handle tasks like network requests, file I/O, and other asynchronous operations in a sequential manner.
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
What is the use of the ‘when’ expression in Kotlin?
The when
expression in Kotlin is a powerful control flow construct that replaces the traditional switch statement found in other languages. It allows for more flexible and expressive conditional branching by supporting arbitrary expressions, ranges, and type checks. Additionally, when
can be used as an expression, returning a value.
fun getDescription(obj: Any): String {
return when (obj) {
is Int -> "Integer"
is String -> "String"
in 1..10 -> "Between 1 and 10"
else -> "Unknown"
}
}
Explain the concept of typealiases in Kotlin.
Typealiases in Kotlin allow you to provide alternative names for existing types, making complex type declarations more readable and easier to manage. They do not create new types but simply provide a shorthand for existing ones.
typealias UserMap = Map<Int, String>
fun printUsers(users: UserMap) {
users.forEach { (id, name) ->
println("User $id: $name")
}
}
What are reified type parameters in Kotlin?
Reified type parameters in Kotlin allow you to access the actual type arguments at runtime within inline functions. This is useful for operations like type checks and reflection, which require type information. To use reified type parameters, the function must be marked with the inline
keyword and the type parameter with reified
.
inline fun <reified T> Gson.fromJson(json: String): T {
return this.fromJson(json, T::class.java)
}
val user: User = gson.fromJson<User>("{"name":"John"}")
What is the difference between open and abstract classes in Kotlin?
In Kotlin, both open
and abstract
classes can be inherited, but there are key differences:
- Open Classes: Can be inherited but can also be instantiated. They may contain both abstract and concrete members.
- Abstract Classes: Cannot be instantiated and must be inherited. They can contain abstract members that must be implemented by subclasses.
How do you handle JSON serialization/deserialization in Kotlin?
JSON serialization and deserialization in Kotlin can be handled using libraries like Gson, Moshi, or Kotlinx Serialization. These libraries provide annotations and functions to convert Kotlin objects to JSON and vice versa. For example, using Kotlinx Serialization:
import kotlinx.serialization.*
import kotlinx.serialization.json.*
@Serializable
data class User(val name: String, val age: Int)
fun main() {
val json = Json.encodeToString(User("Alice", 30))
println(json) // {"name":"Alice","age":30}
val user = Json.decodeFromString<User>(json)
println(user) // User(name=Alice, age=30)
}
What are generics in Kotlin?
Generics in Kotlin allow you to create classes, interfaces, and functions that can operate on types specified as parameters. They enable type-safe code reuse by allowing you to define components that can work with any data type while maintaining compile-time type checking.
fun <T> List<T>.secondOrNull(): T? {
return if (this.size >= 2) this[1] else null
}
val numbers = listOf(1, 2, 3)
println(numbers.secondOrNull()) // 2
Explain the difference between public, private, protected, and internal in Kotlin.
Kotlin provides four visibility modifiers:
- public: Visible everywhere (default).
- private: Visible only within the class or file.
- protected: Visible within the class and its subclasses.
- internal: Visible within the same module.
These modifiers help in encapsulating and controlling access to class members, enhancing code safety and maintainability.
How does Kotlin support operator overloading?
Kotlin allows operator overloading by providing a set of predefined conventions for function names. You can define operator functions using the operator
modifier, enabling you to use standard operators like +
, -
, *
, etc., with custom classes.
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
}
fun main() {
val p1 = Point(1, 2)
val p2 = Point(3, 4)
val p3 = p1 + p2
println(p3) // Point(x=4, y=6)
}
What are inline classes in Kotlin?
Inline classes in Kotlin are a way to create type-safe wrappers around values without the runtime overhead of additional objects. They are declared using the value class
keyword. Inline classes help in optimizing performance by eliminating object allocations where possible.
@JvmInline
value class Email(val address: String)
fun sendEmail(email: Email) {
println("Sending email to ${email.address}")
}
fun main() {
val email = Email("example@example.com")
sendEmail(email)
}