How switching from Java to Kotlin will make your life easier?

Vahan Gevorgyan
Read Priotix
Published in
7 min readDec 4, 2020

Since 2017 Kotlin has become the official language for creating Android applications, but there are still many applications and developers using Java or having legacy code written in Java. Let’s look at the the differences between Java and Kotlin, features that are new in Kotlin and review some tips on how to switch existing Java applications to Kotlin. Kotlin and Java are fully interchangeable so they can be mixed together in one project.

Main syntax differences

Let’s view some parts of a code written in Java and it’s analogue in Kotlin.

First of all, you can notice that there are no semicolons in the Kotlin code, because they are optional for Kotlin.

The default access modifier in Kotlin is public so there is no need to write public keyword. Variable declarations in Kotlin start with val or var keyword, val means that you can’t change its value after declaration, so if you reassign new value to a variable you should use var else val. lateinit modifier means that the property will be assigned later. So the property type is optional if it can be inferred from the initializer. You can see how extending class, declare and override methods, declare interface differs in the syntaxis from the example.

Null safety

By default, all types in Kotlin are not nullable and if a variable can have null values ? should be added at the end of the type declaration. For example, a variable of the String type can not be null, so if it is nullable you should use String? instead. To access properties of a nullable object null should be checked or a safe call operator ?. can be used.

Also for nullable expressions, we have the elvis operator ?: which says “if an expression is not null, use it, otherwise use a non-null value":

Expressions

In Kotlin, if and else can be used as expressions, i.e. return a value. Therefore there is no ternary operator (condition ? then : else), because ordinary if can be used in this role.

In Kotlin when operator is a replacement for switch, it can be used either as an expression or a statement. If when is used as an expression, the else branch is mandatory, unless the compiler can prove that all possible cases are covered with branch conditions (as, for example,we check with enum class entries and sealed class subtypes).

Scope Functions

The Kotlin standard library contains several functions that have a sole purpose -to execute a block of code within the context of an object. When you call such function on an object with a lambda expression provided, it forms a temporary scope. In this scope, you can access the object without its name. Such functions are called scope functions. There are five of them: let, run, with, apply, and also.

Basically, these functions do the following: execute a block of code on an object. What’s difference between them is how this object becomes available inside the block and what is the result of the whole expression is. All the scope functions are quite similar in nature. There are two main differences between each scope function:

  • How the context object is referred to
  • The return value.

Each scope function uses one of two ways to access the context object: as a lambda receiver(this) or as a lambda argument (it). I’ll not go into details of each scope function in this article but using them can reduce the size of a code. Let’s look at an example:hello

Functions

In Kotlin, functions can have default values and naming parameters, so there is no need to use wrapper functions for different sets of parameters.

Kotlin includes in itself all strong aspects of an object-oriented programming language but it also is a functional programming language. Which means that functions can be stored in variables and data structures, passed as arguments to and returned from other functions. A function that takes functions as parameters, or returns a function is called a high-order function. This is a very useful feature, as opposed to Java where it is a common practice to declare interfaces for callback functions. In Kotlin we can pass a callback function as an argument, without declaring interface for that. Let’s review an example where we should pass a click listener to an adapter.

Kotlin also has inline functions that improve performance.

Extension functions

isKotlin provides the ability to extend a class with new functionality without having to inherit from the class or use design patterns such as Decorator. This is done via special declarations called extensions. For example, you can write new functions for a class from a third-party library that you can’t modify. Such functions are available for calling in the usual way as if they were methods of the original class. This mechanism is called extension functions. There are also extension properties that let you define new properties for existing classes.

To declare an extension function for a class, we need to prefix its name with a receiver type, i.e. the type being extended. The following example adds a swap function to MutableList<String>:

The this keyword inside an extension function corresponds to the receiver object (the one that is passed before the dot). Now, we can call such a function as an ordinary method:

This method can also be written as generic:

Object

Object is a new keyword in Kotlin which is an analogue to the singleton pattern in Java. So, you don’t need to implement singleton pattern with the thread safety staff, you simply declare object instead of class. Objects can’t have a constructor and the instance of the object will be created the first time we use it.

Kotlin does not support the static keyword, but you can declare a companion object in that class, that is an object that is common to all instances of that class.

Data class

This is one of my favorite features of Kotlin. Data class is used for DTO (data transfer object) objects. It implements the following functionality:

  • getters (and setters in case of vars) for all properties
  • equals()
  • hashCode()
  • toString()
  • copy()
  • componentN() functions corresponding to the properties in their order of declaration

Sealed Classes

Sealed classes are used to represent restricted class hierarchies, when a value can have one of the types from a limited set, but can’t have any other type. They are, in a sense, an extension of enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances which can contain a state. For example, we can use sealed class to represent a result which can be success or error:

Then you can check the type of result with a when operator:

Collections

In Kotlin the work with collections is simplified. Something similar we can get using Java streams but for that we need a min sdk 26. By default, all collections in Kotlin are immutable and you can’t add or remove elements after creation. Each collection has its mutable version.

Parcelable

In Android to put an object in Bundle, map, set or in other cases when you want to transfer an object (make serializable) you have two choices those are to implement the object from Serializable or implement the object from Parcelable. Parcealble is an Android implementation of Serializable so it is optimized for Android and more effective than Serializable. But for Parcelable in Java you need to implement a lot of stuff, so in most cases Android developers used Serializable because of its easiness of implementation. In Kotlin if you turn on Kotlin experimental features now it is very easy to make an object parcelable. First of all, you need to add in the gradle file following code:

Then if you want to make your data class Parcelable you simply need to implement it and add Parcelize annotation before the class:

Steps from Java to Kotlin in real project

There are also many other differences and new features in Kotlin that I didn’t cover in this blog. If you are working on a real project for many years and you feel that it is time to switch to Kotlin - I’ll give you some advices on how you can do it. It is not a good idea to stop developing new features in application until it will be fully rewritten in Kotlin. You can continue developing your application and rewrite it in Kotlin simultaneously:

  1. Start writing all new classes in Kotlin.
  2. Change all model classes to data classes.
  3. Refactor helper and utility classes to objects.
  4. When during the development you write code in an old class which in Java and you have time to refactor it to Kotlin, do it.
  5. You can start to refactor some layers of the application, e.g. all repository classes.
  6. When there will be so little Java code left that you can refactor it in 1–2 days, refactor it all.

This process could take a long time and during that you’ll be forced to use a mixed Java and Kotlin code in the app, but you’ll continue to develop your app features and in the end you will switch your app from Java to Kotlin without extra time efforts.

--

--