Kotlin Some important unsorted interview questions and answers
What is inline class in Kotlin and when do we need one? Provide an example. What is inline class in Kotlin and when do we need one? Provide an example.
Sometimes it is necessary for business logic to create a wrapper around some type. However, it introduces runtime overhead due to additional heap allocations. Moreover, if the wrapped type is primitive, the performance hit is terrible, because primitive types are usually heavily optimized by the runtime.
Inline classes provide us with a way to wrap a type, thus adding functionality and creating a new type by itself. As opposed to regular (non-inlined) wrappers, they will benefit from improved performance. This happens because the data is inlined into its usages, and object instantiation is skipped in the resulting compiled code.
inline class Name(val s: String) {
val length: Int
get() = s.length
fun greet() {
println("Hello, $s")
}
}
fun main() {
val name = Name("Kotlin")
name.greet() // method `greet` is called as a static method
println(name.length) // property getter is called as a static method
}
Some notes about inline classes:
- A single property initialized in the primary constructor is the basic requirement of an inline class
- Inline classes allow us to define properties and functions just like regular classes
- Init blocks, inner classes, and backing fields are not allowed
- Inline classes can inherit only from interfaces
- Inline classes are also effectively final
Explain the difference between Inline classes vs type aliases ☆☆☆☆
Answer: The crucial difference is that type aliases are assignment-compatible with their underlying type (and with other type aliases with the same underlying type), while inline classes are not.
In other words, inline classes introduce a truly new type, contrary to type aliases which only introduce an alternative name (alias) for an existing type:
typealias NameTypeAlias = String
inline class NameInlineClass(val s: String)
fun acceptString(s: String) {}
fun acceptNameTypeAlias(n: NameTypeAlias) {}
fun acceptNameInlineClass(p: NameInlineClass) {}
fun main() {
val nameAlias: NameTypeAlias = ""
val nameInlineClass: NameInlineClass = NameInlineClass("")
val string: String = ""
acceptString(nameAlias) // OK: pass alias instead of underlying type
acceptString(nameInlineClass) // Not OK: can't pass inline class instead of underlying type
// And vice versa:
acceptNameTypeAlias(string) // OK: pass underlying type instead of alias
acceptNameInlineClass(string) // Not OK: can't pass underlying type instead of inline class
}
How would you refactor this code using "apply"? How would you refactor this code using "apply"?
Consider:
class Message(message: String, signature: String) {
val body = MessageBody()
init {
body.text = message + "\n" + signature
}
}
Do you see any refactoring that could be done?
You can write:
class Message(message: String, signature: String) {
val body = MessageBody().apply {
text = message + "\n" + signature
}
}
What are Object expressions in Kotlin and when to use them? What are Object expressions in Kotlin and when to use them?
Sometimes we need to create an object of some class with slight modification, without explicitly declaring a new subclass for it. Java handles this case with anonymous inner classes. Kotlin uses object expression to achieve the same functionality. We can even create an object expression for an interface or abstract class by just implementing their abstract methods.
It is often used as a substitution to a Java anonymous class:
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// ...
}
override fun mouseEntered(e: MouseEvent) {
// ...
}
})
What is the difference between “*” and “Any” in Kotlin generics? What is the difference between “*” and “Any” in Kotlin generics?
List<*>
can contain objects of any type, but only that type, so it can containStrings
(but onlyStrings
)- while
List<Any>
can containStrings
andIntegers
and whatnot, all in the same list
Imagine you moving your code from Java to Kotlin. How would you rewrite this code in Kotlin? Imagine you moving your code from Java to Kotlin. How would you rewrite this code in Kotlin?
public class Foo {
private static final Logger LOG = LoggerFactory.getLogger(Foo.class);
}
Use Static-like approach:
class MyClass {
companion object {
val LOG = Logger.getLogger(MyClass::class.java.name)
}
fun foo() {
LOG.warning("Hello from MyClass")
}
}
How Kotlin coroutines are better than RxKotlin/RxJava? How Kotlin coroutines are better than RxKotlin/RxJava?
Kotlin coroutines are different from Rx. Both are designed to address a problem of asynchronous programming, however their approach to solution is very different:
Rx comes with a particular functional style of programming that can be implemented in virtually any programming language without support from the language itself. It works well when the problem at hand easily decomposes into a sequence of standard operators and not so well otherwise.
Kotlin coroutines provide a language feature that let library writers implement various asynchronous programming styles, including, but not limited to functional reactive style (Rx). With Kotlin coroutines you can also write your asynchronous code in imperative style, in promise/futures-based style, in actor-style, etc.
How Kotlin coroutines are better than RxKotlin? You just write sequential code, everything is as easy as writing synchronous code except it execute asynchronously. It's easier to grasp.
Coroutines are better to deal with resources
- In RxJava you can assign computations to schedulers but
subscribeOn()
andObserveOn()
are confusing. Every coroutine is given a thread context and return to parent context. For a channel, both side (producer, consumer) execute on his own context. Coroutines are more intuitive on thread or thread pool affectation. - Coroutines give more control on when those computation occur. You can for example pass hand (
yield
), prioritize (select
), parallelize (multipleproducer
/actor
onchannel
) or lock resource (Mutex
) for a given computation. It may not matter on server (where RxJava came first) but on resources limited environment this level of control may be required. - Due to it's reactive nature, backpressure doesn't fit well in RxJava. In the other end
send()
to channel is a suspensive function that suspend when channel capacity is reached. It's out-of-the-box backpressure given by nature. You could alsooffer()
to channel, in which case the call never suspend but returnfalse
in case the channel is full, effectively reproducingonBackpressureDrop()
from RxJava. Or you could just write your own custom backpressure logic, which won't be difficult with coroutines, especially compared to do the same with RxJava.
What is the difference between launch/join and async/await in Kotlin coroutines? What is the difference between launch/join and async/await in Kotlin coroutines?
launch is used to** fire and forget coroutine**. It is like starting a new thread. If the code inside the
launch
terminates with exception, then it is treated like uncaught exception in a thread -- usually printed to stderr in backend JVM applications and crashes Android applications.join
is used to wait for completion of the launched coroutine and it does not propagate its exception. However, a crashed child coroutine cancels its parent with the corresponding exception, too.async is used to start a coroutine that computes some result. The result is represented by an instance of
Deferred
and you must useawait
on it. An uncaught exception inside the async code is stored inside the resultingDeferred
and is not delivered anywhere else, it will get silently dropped unless processed. You MUST NOT forget about the coroutine you’ve started with async.
How to implement Builder pattern in Kotlin? How to implement Builder pattern in Kotlin?
First and foremost, in most cases you don't need to use builders in Kotlin because we have default and named arguments but if you need one use:
class Car( //add private constructor if necessary
val model: String?,
val year: Int
) {
private constructor(builder: Builder) : this(builder.model, builder.year)
class Builder {
var model: String? = null
private set
var year: Int = 0
private set
fun model(model: String) = apply { this.model = model }
fun year(year: Int) = apply { this.year = year }
fun build() = Car(this)
}
}
Usage:
val car = Car.Builder().model("X").build()
What is the use of @JvmStatic, @JvmOverloads, and @JvmFiled in Kotlin?
- @JvmStatic: This annotation is used to tell the compiler that the method is a static method and can be used in Java code.
- @JvmOverloads: To use the default values passed as an argument in Kotlin code from the Java code, we need to use the
@JvmOverloads
annotation. - @JvmField: To access the fields of a Kotlin class from Java code without using any getters and setters, we need to use the
@JvmField
in the Kotlin code.
Learn more about @JvmStatic, @JvmOverloads, and @JvmField in Kotlin from MindOrks blog.
What do you mean by destructuring in Kotlin?
Destructuring is a convenient way of extracting multiple values from data stored in(possibly nested) objects and Arrays. It can be used in locations that receive data (such as the left-hand side of an assignment). Sometimes it is convenient to destructure an object into a number of variables, for example:
val (name, age) = developer
Now, we can use name and age independently like below:
println(name)
println(age)
What are lambdas expressions?
Lambdas expressions are anonymous functions that can be treated as values i.e. we can pass the lambdas expressions as arguments to a function return them, or do any other thing we could do with a normal object. For example:
val add : (Int, Int) -> Int = { a, b -> a + b }
val result = add(9, 10)
What are pair and triple in Kotlin?
Pair and Triples are used to return two and three values respectively from a function and the returned values can be of the same data type or different.
val pair = Pair("My Age: ", 25)
print(pair.first + pair.second)
Learn more about Pairs and Triples from MindOrks blog.
What are labels in Kotlin?
Any expression written in Kotlin is called a label. For example, if we are having a for-loop in our Kotlin code then we can name that for-loop expression as a label and will use the label name for the for-loop.
We can create a label by using an identifier followed by the @
sign. For example, name@
, loop@
, xyz@
, etc. The following is an example of a label:
loop@ for (i in 1..10) {
// some code goes here
}
The name of the above for-loop is loop
.
Describe Kotlin’s Interoperability with JavaScript
During many Kotlin interview questions, interviewees are asked about the degree of flexibility Kotlin allows for JavaScript applications. Kotlin enables Android and iOS devs to seamlessly target JavaScript. What this means is, you can easily trans-compile a program written in Kotlin to native JavaScript code. This allows developers to easily create software for the popular Node.JS platform.
Kotlin enables developers to control all elements of JS programming- such as manipulating the DOM, leveraging graphics, managing the server-side, and so on. Additionally, you can utilize Kotlin with existing JS libraries like jQuery, and React. Visit this guide for detailed information about Kotlin to JavaScript trans-piling.
List Some Features of Kotlin that are Absent in Java
Sometimes Kotlin interview questions are designed in a way that helps companies understand the potential of future employees. Below, we’re listing some functionalities of Kotlin that are simply unavailable in the Java programming language.
- Null Safety – a flagship feature of Kotlin
- Co-Routines – enables asynchronous programming
- Operator Overloading – a key feature missing in Java
- Smart Casts – allows casting inferences
- Companion Object – another useful functionality
How to Migrate Java Code to Kotlin?
It’s possible for us to migrate existing Java codes to Kotlin easily using the IntelliJ IDEA from JetBrains. The below section demonstrates how to do this in a sequence.
- Update the build file to support Kotlin compilation
- Open the necessary .java file using IDEA
- Copy all the required code snippets
- Create a Kotlin file ending with .kt
- Paste the code snippets in this Kotlin file
- Enter Yes when IDEA asks if it should convert the Java code to Kotlin
Visit this official guide to learn more about this issue.
Why doesn’t Kotlin Feature Macros?
Macros are useful in a number of programming scenarios. However, they tend to create a mess of your project and often confuse new developers. This is why JetBrains, the developers behind Kotlin omitted this feature altogether. Moreover, developers often find it hard to test or optimize codebases that contain a lot of macros. So, omitting macros is a design decision. Ther developers of Kotlin are, however, working on features like serialization and compiler plugins to address some shortcomings of this decision.
Is It Possible to Execute Kotlin Code without JVM?
As we’ve mentioned many times already, Kotlin compiles into bytecode and runs on top of the Java Virtual Machine(JVM). However, it’s also possible to compile Kotlin into native machine code and thus execute successfully without requiring any JVM at all.
Developers can use the Kotlin/Native tool for doing this effortlessly. It’s an effective LLVM backend that allows us to create standalone executables. It exposes some additional functionalities as well. Consult their official documentation for more information.
Write a Kotlin Program to Display the Fibonacci Series
Most Kotlin interview questions aim to find out the knowledge of the candidates for practical problems. The Fibonacci series is a common question faced by job seekers in many Kotlin interviews. It’s a mathematical sequence of numbers where each number is the sum of its previous two numbers.
fun main(args: Array<String>) { val range = 10 var firstNumber = 0 var secondNumber = 1 print("First $range numbers of Fibonacci series: ") for (i in 1..range) { print("$firstNumber + ") val sum = firstNumber + secondNumber firstNumber = secondNumber secondNumber = sum } }
We’ve used a for loop for computing this series. However, you can solve this problem by using several strategies.
Write a Program for Determining if a Number is Prime or Not
Prime numbers play a major role in modern computing, particularly in number theory. Software developers usually use them to implement safe encryption mechanisms for their applications. We’re illustrating a simple Kotlin program that determines whether a particular number is prime or not.
fun main( args: Array<String> ) { print("Enter the number:") var num = readLine()!!.toIntOrNull() var flag = false if( num != null ){ for (i in 2..num / 2) { if (num % i == 0) { flag = true break } } } if (flag) println("$num is not a prime number.") else println("$num is a prime number.") }
39. Write a Program for Finding the Sum of Natural Numbers
Natural numbers are all positive values starting from 1. The sum of these numbers can be easily calculated using the Kotlin’s loop constructs. Below, we’re demonstrating a simple program that takes user input and calculates the sum of all natural numbers up to that point.
fun main( args: Array<String> ) { print("Enter the number:") var num = readLine()!!.toIntOrNull() var sum = 0 // inital value of summation if( num != null ){ for (i in 1..num) { sum += i } println("Sum = $sum") } }
Find Factorial of Numbers using Recursion
The factorial of a number is defined as the product of all numbers starting at 1 and up to that number. We can easily write a Kotlin program to do this job using either loops or recursion. The latter is a divide and conquer programming strategy which divides a routine into multiple similar but small sub-routines.
fun main(args: Array<String>) { print("Enter the number:") val number = readLine()?.toInt() if(number != null ){ val factorial = multiplyNums(number) println("Factorial of $number = $factorial") } } fun multiplyNums(number: Int): Long { if (number >= 1) return number * multiplyNums(number - 1) // recursive call to multiplyNums else return 1 }
How do Destructuring Declarations Work in Kotlin?
Kotlin allows developers to assign multiple values to variables from data stored in objects or arrays. It’s a very smart feature and employers often ask about this during Kotlin interview questions. We’re demonstrating a quick example below to help you understand this concept more clearly.
data class Book(val name: String, val publication: String){ } fun main(args: Array<String>) { val (name, publication) = Book("Kotlin for Dummies", "O’Reilly") println(name) println(publication) }
When compiled, this program will return the name and publication of the book from the specified data class. The destructuring takes place in the first line inside the main function.
Write a Program to Swap Two Numbers Without Using Temporary Variables
Swapping two numbers using a temporary variable is a common practice for many. However, we can easily swap values among variables without using any such variables. Take a look at the below Kotlin program to find out how to do this in action.
fun main(a: Array<String>) { var variable1 = 10 var variable2 = 20 println("Before swapping:") println("First variable has: $variable1") println("Second variable has: $variable2") variable1 = variable1 + variable2 variable2 = variable1 - variable2 variable1 = variable1 - variable2 println("After swapping:") println("First variable contains: $variable1") println("Second variable contains: $variable2") }
Write a Kotlin Program for Calculating the Power of a Number
Many programming logic uses the power of a number for achieving its end goal. Thankfully, calculating the power of a given number is effortless in Kotlin. The below program demonstrates a simple program for this purpose. It is based on recursion.
fun main(args: Array<String>) { print("Enter the base:") val base = readLine()!!.toInt() print("Enter the power:") val power = readLine()!!.toInt() val result = powerRaised(base, power) println("$base^$power = $result") } fun powerRaised(base: Int, power: Int): Int { if (power != 0) return base * powerRaised(base, power - 1) else return 1 }
What is basic difference between fold and reduce in Kotlin? When to use which?
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
and 1
.
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
and 2
Comments
Post a Comment