Benefits of Kotlin over Java: Backend and Android
Ever since I have shifted to Kotlin I have never looked back!
Before We Begin
I have been using Kotlin for a while now and I believe it has the right set of features for developers. I will be sharing the features that worked really well for both Spring Boot Backend and Android. But before getting into that, let's start from the basics.
What is Kotlin?
Kotlin is a general-purpose, open-source, statically typed programming language for the JVM, Browser, Native, and Android that combines object-oriented and functional programming features.
Fun Fact
The name comes from Kotlin Island, near St. Petersburg. Andrey Breslav mentioned that the team decided to name it after an island just like Java was named after the Indonesian island of Java.
Some More facts
Kotlin’s growth has been doubling each year until 2015 when the first massive spike in its usage happened.
Google announced that Kotlin was officially supported for Android and a massive number of Android developers started using Kotlin.
It’s taken seriously by Gradle build tool
Old-time players like Spring are supporting Kotlin
In the official studies conducted by JetBrains, two questions were asked and these were the outcomes.
1. How do you mostly use Kotlin?
Source: https://www.jetbrains.com/research/kotlin-census-2018/
2. What’s stopping you from using Kotlin in production?
Source: Source: https://www.jetbrains.com/research/kotlin-census-2018/
It is clearly visible that a lot of people have already started using it in production. And the major reason for people to not use it is the lack of knowledge. I hope this blog post can help reduce the “lack of knowledge” percentage and make people more comfortable using Kotlin in production.
Null Safety Is A Blessing
This is one of the best features of Kotlin. It reduces so much overhead for a developer and makes you write code that is safe. Kotlin’s type system is aimed at eliminating the danger of null references from code, also known as The Billion Dollar Mistake.
We can still have fields that can be null
but we have to explicitly declare that and that's how the compiler will always complain if you do not handle it properly.
The problem with the NPE (Null Pointer Exception) is its ability to creep in the codebase. And more often than not your application throws it during runtime when your users are actually using the app.
With the safe operator ?.
, you can easily handle that explicitly.
**Java**
if (text != null) {
int length = text.length();
}
**Kotlin**
text?.let {
val length = text.length
}
// or simply
val length = text?.length
And to handle the null case you can use Elvis operator ?:
val result = nullableVariable**?.**someMethodCall()
**?:** fallbackIfNullMethodCall()
Sealed Classes for Restricted Hierarchies
Sealed classes are Kotlin’s way of providing you a way to limit the types of a class when a value can have one of the types from a limited set.
sealed **class** Operation {
** class** Add(val value: Int) : Operation()
** class** Substract(val value: Int) : Operation()
}
And then simply use the when expression to evaluate conditions for each of the types. If you miss any type, the compiler will complain. This reduces the amount of code you write
fun **execute**(x: Int, op: Operation) = **when** (op) {
**is** Operation.Add -> x + op.value
**is** Operation.Substract -> x - op.value
}
Most of the backend codebases will have some sort of analytics tracking to track the behaviour of your users or system. Using sealed classes to create a set of events that you would trigger would be a good way to ensure all the events have a consistent format. The when
expression will then ensure that you have not missed any of the Events during compile time.
Another good use of sealed classes in Android is to handle the UI states. Let’s say you have three states for your activity — Loading, Data, NoData. You can create a sealed class UIState
and handle them in the activity. You can learn more about using sealed classes for Android here.
Immutability is the Default Setting
In Kotlin, we should always use val
to declare a variable. This creates an immutable variable. In Java, we have to add the additional keyword final
(again, syntactic noise!). If your variable really has to be mutable, you can use var
. But think twice before you use var
.
**val** immutableName = "Name"
immutableName = "New name" *// compile error!
***var **mutableName** **= "Name"
mutableName = "New Name"
As a developer, you gain a lot of confidence writing code when you know your variables are not going to be manipulated unless you declare them like that.
Just like variable reference, collections are immutable by default, and data classes are immutable as well.
val list = *listOf*(1,2,3,4)
list.add(1) *//compile error.*
You still have the mutable collections which can be declared prefixing mutable in front of the collection.
val list = *mutableListOf*(1,2,3,4)
list.add(1)
Late Initialization of Properties
The modifier **lateinit
* allows us to delay the initialization of a variable. Very useful when the dependencies are initialized by the DI (Dependency Injection) framework*, which happens during runtime.
It comes in very handy for testing as most of the classes are mocked. Like in the case of Spring Boot when your dependencies are provided by Spring.
@Mock
lateinit var myRepository: MyRepository
If you use Dagger, you might be used to code snippets similar to the following one:
@Inject
lateinit var myVar: MyObject
The variable is actually not initialized but injected afterward. By using **lateinit
** we allow the initialization to happen later. This reduces the number of unnecessary null checks.
Less Boilerplate is Definitely a Plus
This is one of the first arguments that favour Kotlin in a huge way. Kotlin reduces a lot of code that you write and never look at. It is designed very well for major use cases. For example, data classes readily provide equals, hashCode, toString, and copy functions.
// Java
public class Price {
String amount;
String currency;
public Price(String amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}
// Kotlin
data class Price(val amount: String, val currency: String)
Few Things to Be Aware Of
I have faced a few issues with using Hibernate with Kotlin because all the classes are
final
by default. To circumvent that you need to add a few dependencies and plugins. Here is the link that has detailed information.Name shadowing can really turn into a nightmare at times, and those are only warnings from the compiler. When your code becomes too nested, it becomes harder to read.
Kotlin did a good job of reducing the boilerplate code and make everything concise, but that sometimes leads to very high information density.
Final Thoughts
The more I write applications with Kotlin, the more I feel comfortable with it. It has allowed me to write applications more efficiently with expressive, short, and readable code, and using it has been a real pleasure.
And just like any other language, when you start it for the first time, it feels confusing and alien. But Kotlin looked the least confusing, most constructs were pretty easy to understand and remember. I have worked in Java, Go, and a little bit of Python, but this one has been my favorite to date.
I absolutely recommend learning it and using it.
Links to popular Kotlin concepts.