From Java to Kotlin — The good, the bad and the misunderstood

In 2019 I started coding in Kotlin, our team had several reasons to try it out:

  • We were creating a new set of services so had a chance to embed some new languages, techniques and frameworks
  • We heard multiple positive reviews about Kotlin

Java and I

I’ve been coding in Java for many years and it became my main programming language in 2008. I like Java, I enjoy coding in Java, but I have to keep up. I tried Scala, but after trying to learn it I came to the realisation that it is not my style.

The services

The services are small Spring + boot applications, implementing REST controllers with a lot of I/O (disk and database), the services themselves are quite isolated and can be considered micro.

Some meta about Kotlin

Kotlin is a JVM language, it is statically-typed and object-oriented. Kotlin was developed by Jetbrains, which to me shows some promise because who’s better in understanding the programmers’ needs than the ones that develop the IDE.

By describing what I liked (or disliked) I will try to give you an overview of what it’s like to program in Kotlin.

The good

Nulls

In Kotlin a variable or a method’s returned value is not necessarily nullable, in fact the intuitive code would make a variable not nullable.

var s: String = "foo"

Trying to assign null to the variable s will not compile.

However, the following code snippet does compile.

var s: String? = null

Now, try to use the variable and your compiler alerts you that value may be null.

The chances of you getting a NullPointerException are limited to:

s!!.<do something>

Meaning, you are telling the compiler that you are (pretty) sure there is no null, and you’d like to use the value.

In my opinion, this approach to null and nullable variables is a lot better then the Optional object. My code is a lot safer because I have to think about the possible values of each variable.

Extensions!

Kotlin added functionality that allows you to extend classes by adding:

  • Methods
  • Properties

Relax, this is not a rebranding of the inheritance. Inheritance is still there where you left it, but sometimes you have a final class and you’d like to add some functions and properties to it, right? Or even better, use a helpful method that someone else wrote. If you are like me you probably wrote many utility classes and static methods, and also used libraries like apache-commons, Guava and other popular utility libraries. But, that is a bit ugly, right?

Kotlin introduces a different approach to it, it allows you to extend classes without inheriting from them, by adding the methods and properties you just need. The following code:

fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // ‘this’ corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}

Will allow you to do the following:

val list = mutableListOf(1, 2, 3)
list.swap(0, 2)

You are probably wondering at this point: “How is it even possible?!”. You are right, it isn’t. The extension methods are compiled to static methods. But, in my opinion, this results in nicer and more readable code.

Extension properties work similarly, but note that you can only read from them and not set their values.

The bonus is that the Kotlin distribution already contains some very useful extensions that you will enjoy without even being aware of them being extensions.

The bad

I could not find something to label as bad, but I did find some frustration.

Generics

Working with Java I would often use the wildcard types, some might say it is tricky but I find it very useful. Wildcards solve a specific problem — in Java this is not allowed:

interface Source<T> {
T nextT();
}
void demo(Source<String> strs) {
Source<Object> objects = strs;
}

To solve that most programmers would say that T extends Object, Kotlin came to solve this issue with a different approach but that made the wildcards not necessary.

I am not sure that having wildcards is a must, but I did not think I would have a problem and ended up very frustrated trying to write the code “as I’m used to” and not understanding why it’s not working or how to change it to get it to work. The simple answer is I had to learn a new technique and let go of the one I’ve known so far.

Kotlin distinguishes between two kinds of generic types:

  • in
  • out

Out

T is not a parameter in any method, so declaring it as an out variant makes the assignment legal. This translates in Kotlin to:

interface Source<out T> {
fun nextT(): T
}
fun demo(strs: Source<String>) {
val objects: Source<Any> = strs
}

In

On the other hand if T is only a parameter it can be declared as in making this valid:

interface Comparable<in T> {
operator fun compareTo(other: T): Int
}
fun demo(x: Comparable<Number>) {
x.compareTo(1.0) // 1.0 has type Double, a subtype of Number
// Thus, we can assign x to a variable of type Comparable<Double>
val y: Comparable<Double> = x // OK!
}

So, why was I so lost? The examples are very simple, but my classes can’t always be simple. When I had classes that are not so clean I started to get flustered with the explanations and tutorials. Perhaps it is easier if you start with Kotlin, because the result is different class design.

The misunderstood

Mutability or Immutability?

Not so misunderstood but more “I prefer the Java style”. Variables in Kotlin have two types:

  • val — Value meaning immutable
  • var — Variable meaning the value can change

I find myself confusing these two, I preferred using Java’s final.

Varargs

I normally don’t use varargs, though it is a nice feature. But when you have generated code in your application your code may have some varargs in it without your control.
Our application used JOOQ, which generates some Java classes and apparently by default the code would have varargs usages.

No problemo my friend, all we needed was to send the array values. In Java, arrays are perfectly legal for varargs method signatures. The compiler just “knows”.

Not in Kotlin, I do not know why but it just doesn’t. If you really need it you have to tell the compile to expand/spread the array.

So, what we thought would be:

myVarArgsMethod(myArray)

Does not compile, we had to change it to:

myVarArgsMethod(*myArray);

The asterisk (‘*’) sign means expand/spread an array. To us it just looked ugly, so we configured JOOQ to not generate varargs signatures with the property:

varargSetters = false

Well, that was a waste of half a day.

I am aware of the fact that this kind of a feature is available in other languages, for example JavaScript ES6 (3 dots). But, when transitioning from Java to Kotlin it was just plain confusing.

Summary

In hindsight I look at my Kotlin experience as very positive and I find myself going to Kotlin instead of Java, when working on my projects.

We were told that we can put the Java and Kotlin classes in the same module under different directories. However, we had some difficulties with the Intellij plugin for Gradle and we ended up separating modules for code in different languages.

Following this experience, I recommend starting to use Kotlin for backend programming.

Who I am

My name is Sigal Shaharabani — I am a senior data backend developer in Tikal.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store