Kotlin is a cross-platform, statically typed, general-purpose programming language with type inference. Kotlin is designed to interoperate fully with Java, and the JVM version of Kotlin's standard library depends on the Java Class Library, but type inference allows its syntax to be more concise. Kotlin mainly targets the JVM, but also compiles to JavaScript for frontend web applications using React or native code (via LLVM), e.g. for native iOS apps sharing business logic with Android apps. Follow along to check the most complete and comprehensive collection of the most common and advanced Kotlin Interview Questions every Android developer should know in 2021.
You can also find all 68 answers here ππΌ https://devinterview.io/dev/kotlin-interview-questions
We frequently create classes whose main purpose is to hold data. In Kotlin, this is called a data class and is marked as data
:
data class User(val name: String, val age: Int)
To ensure consistency and meaningful behavior of the generated code, data classes have to fulfill the following requirements:
- The primary constructor needs to have at least one parameter;
- All primary constructor parameters need to be marked as val or var;
- Data classes cannot be abstract, open, sealed or inner;
In Java an array can be initialized such as:
int numbers[] = new int[] {10, 20, 30, 40, 50}
How does Kotlin's array initialization look like?
val numbers: IntArray = intArrayOf(10, 20, 30, 40, 50)
How to remove duplicates from an Array<String?>
in Kotlin?
Use the distinct
extension function:
val a = arrayOf("a", "a", "b", "c", "c")
val b = a.distinct() // ["a", "b", "c"]
You can also use:
toSet
,toMutableSet
toHashSet
- if you don't need the original ordering to be preserved
These functions produce a Set
instead of a List
and should be a little bit more efficient than distinct.
Use var where value is changing frequently. For example while getting location of android device:
var integerVariable : Int? = null
Use val where there is no change in value in whole class. For example you want set textview or button's text programmatically.
val stringVariables : String = "Button's Constant or final Text"
fold
takes an initial value, and the first invocation of the lambda you pass to it will receive that initial value and the first element of the collection as parameters.listOf(1, 2, 3).fold(0) { sum, element -> sum + element }
The first call to the lambda will be with parameters
0
and1
.Having the ability to pass in an initial value is useful if you have to provide some sort of default value or parameter for your operation.
reduce
doesn't take an initial value, but instead starts with the first element of the collection as the accumulator (calledsum
in the following example)listOf(1, 2, 3).reduce { sum, element -> sum + element }
The first call to the lambda here will be with parameters
1
and2
.
The primary constructor is part of the class header. Unlike Java, you don't need to declare a constructor in the body of the class. Here's an example:
class Person(val firstName: String, var age: Int) {
// class body
}
The main idea is by removing the constructor keyword, our code gets simplified and easy to understand.
In Kotlin, you can concatenate 1. using string interpolation / templates
val a = "Hello"
val b = "World"
val c = "$a $b"
using the + /
plus()
operatorval a = "Hello" val b = "World" val c = a + b // same as calling operator function a.plus(b) val c = a.plus(b)
print(c)
using the
StringBuilder
val a = "Hello" val b = "World"
val sb = StringBuilder() sb.append(a).append(b) val c = sb.toString()
print(c)
var is like
general
variable and it's known as a mutable variable in kotlin and can be assigned multiple times.val is like
Final
variable and it's known as immutable in Kotlin and can be initialized only single time.
+----------------+-----------------------------+---------------------------+
| | val | var |
+----------------+-----------------------------+---------------------------+
| Reference type | Immutable(once initialized | Mutable(can able to change|
| | can't be reassigned) | value) |
+----------------+-----------------------------+---------------------------+
| Example | val n = 20 | var n = 20 |
+----------------+-----------------------------+---------------------------+
| In Java | final int n = 20; | int n = 20; |
+----------------+-----------------------------+---------------------------+
Just use object
.
object SomeSingleton
The above Kotlin object will be compiled to the following equivalent Java code:
public final class SomeSingleton { public static final SomeSingleton INSTANCE;
private SomeSingleton() { INSTANCE = (SomeSingleton)this; System.out.println("init complete"); }
static { new SomeSingleton(); } }
This is the preferred way to implement singletons on a JVM because it enables thread-safe lazy initialization without having to rely on a locking algorithm like the complex double-checked locking.
A blocking call to a function means that a call to any other function, from the same thread, will halt the parentβs execution. Following up, this means that if you make a blocking call on the main threadβs execution, you effectively freeze the UI. Until that blocking calls finishes, the user will see a static screen, which is not a good thing.
Suspending doesnβt necessarily block your parent functionβs execution. If you call a suspending function in some thread, you can easily push that function to a different thread. In case it is a heavy operation, it wonβt block the main thread. If the suspending function has to suspend, it will simply pause its execution. This way you free up its thread for other work. Once itβs done suspending, it will get the next free thread from the pool, to finish its work.
Mutable and immutable list increase the design clarity of the model.
This is to force developer to think and clarify the purpose of collection.
- If the collection will change as part of design, use mutable collection
- If model is meant only for viewing, use immutable list
Purpose of val
and var
is different from immutable and mutable list.
val
and var
keyword talk about the how a value/reference of a variable should be treated.
var
- value/reference assigned to a variable can be changed at any point of time.val
- value/reference can be assigned only once to a variable and can't be changed later point in the execution.
There are several reasons why immutable objects are often preferable:
- They encourage functional programming, where state is not mutated, but passed on to the next function which creates a new state based on it. This is very well visible in the Kotlin collection methods such as map, filter, reduce, etc.
- A program without side effects is often easier to understand and debug (you can be sure that the value of an object will always be the one at its definition).
- In multithreaded programs, immutable resources cannot cause race conditions, as no write access is involved.
You have also some disadvantages:
- Copying entire collections just to add/remove a single element is computationally expensive.
- In some cases, immutability can make the code more complex, when you tediously need to change single fields. In Kotlin, data classes come with a built-in copy() method where you can copy an instance, while providing new values for only some of the fields.
lateinit means late initialization. If you do not want to initialize a variable in the constructor instead you want to initialize it later on and if you can guarantee the initialization before using it, then declare that variable with lateinit keyword. It will not allocate memory until initialized. You cannot use lateinit for primitive type properties like Int, Long etc.
lateinit var test: String
fun doSomething() { test = "Some value" println("Length of string is "+test.length) test = "change value" }
There are a handful of use cases where this is extremely helpful, for example:
- Android: variables that get initialized in lifecycle methods;
- Using Dagger for DI: injected class variables are initialized outside and independently from the constructor;
- Setup for unit tests: test environment variables are initialized in a
@Before
- annotated method; - Spring Boot annotations (eg.
@Autowired
).
Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on variables of this type.
The extension functions dispatched statically. That means the extension function which will be called is determined by the type of the expression on which the function is invoked, not by the type of the result of evaluating that expression at runtime. In short, they are not virtual by receiver type.
Consider:
open class BaseClass
class DerivedClass : BaseClass()
fun BaseClass.someMethod(){ print("BaseClass.someMethod") }
fun DerivedClass.someMethod(){ print("DerivedClass.someMethod") }
fun printMessage(base : BaseClass){ base.someMethod() }
printMessage(DerivedClass())
This will print
BaseClass.someMethod
because the extension function being called depends only on the declared type of the parameter base
in printMessage
method, which is the BaseClass
class. This is different from runtime polymorphism as here it is resolved statically but not at the runtime.
Java vs Kotlin | Java | Kotlin |
Null Safe | In Java, NullPointerExceptions causes huge frustration for developers. It allows users to assign null to any variables but while accessing an object reference having null value raises a null pointer exception which user needs to handle. | In Kotlin, By default, all types of variables are non-null able (i.e. we canβt assign null values to any type of variables/objects). If we try to assign or return null values, Kotlin code will fail during compile-time. If we really want a variable to have a null value, we can declare as follows: value num: Int? = null |
Extension Functions | In Java, If we want to extend the functionality of existing class we need to create a new class and inherit the parent class. So Extension functions are not available in Java | Kotlin provides developers the ability to extend an existing class with new functionality. We can create extend functions by prefixing the name of a class to name of the new function. |
CoroutinesΒ Support | In Java, whenever if we initiate a long-running network I/0 or CPU Intensive operations, the corresponding thread will be blocked. As Android is a single-threaded by default. Java provides the ability to create multiple threads in the background and run but managing them is a complex task. | In Kotlin, We can create multiple threads to run these long-running intensive operations but we have coroutines support, which will suspend execution at a certain point without blocking threads while executing long-running intensive operations. |
No checked exceptions | In Java, We have checked exceptions support which makes developers declare and catch the exception which ultimately leads to robust code with good error handling. | In Kotlin, we donβt have checked exceptions. So developers donβt need to declare or catch the exceptions, which have advantages and disadvantages. |
Data classes | In Java, suppose we need to have a class which needs to hold data but nothing else. For this we need to define constructors, variables to store data, getter and setter methods, hashcode(), toString(), and equals() functions | In Kotlin, If we need to have classes which need to hold data we can declare a class with keyword βdataβ in the class definition then the compiler will take care of all of this work such as creating constructors, getter, setter methods for different fields. |
Smart casts | In Java, We need to check the type of variables and cast according to our operation. | In Kotlin, smart casts will handle these casting checks with keyword βis-checksβ which will check for immutable values and performs implicit casting. |
Type inference | In Java, we need to specify a type of each variable explicitly while declaring. | In Kotlin, we donβt need to specify the type of each variable explicitly based on assignment it will handle. If we want to specify explicitly we can do. |
Functional Programming | Java doesnβt have functional programming support till Java 8 but while developing Android applications it supports the only subset of Java 8 features. | Kotlin is a mix of procedural and functional programming language which consists of many useful methods such as lambda, operator overloading, higher-order functions, and lazy evaluation, etc. |
const
s are compile time constants. Meaning that their value has to be assigned during compile time, unlike val
s, where it can be done at runtime.
This means, that const
s can never be assigned to a function or any class constructor, but only to a String
or primitive.
For example:
const val foo = complexFunctionCall() //Not okay val fooVal = complexFunctionCall() //Okay
const val bar = "Hello world" //Also okay