I often see developers on http://slack.kotlinlang.org/ wondering which of their code snippets is more performant. Usually, one of the snippets is similar to how things are done in Java while the other is a more Kotlin idiomatic way. Generally, the assumption tends to be that, by adding syntactic sugar, “the Kotlin way” is slower than the more verbose “Java way”. It is not always true.
Having a Java development background, whenever I am tasked with benchmarking performance of a code block/method, I automatically think of doing this:
How many times have you had to write something similar in Java thinking that there must be a better way?
The better way is finally here and, again, it comes from Kotlin.
More intuitive and concise code, no math (albeit basic) all mean less chance of making an error when writing code.
Note, measureTimeMillis (as well as measureNanoTime) is a standard library function. In Kotlin, when a function takes a lambda as the last argument, the latter may be supplied after the function call like so:
And because there are no additional arguments passed into the function, the parentheses may be omitted altogether:
Let’s see an example usage. We will compare performance between the basic for loop and the forEach function from Kotlin’s standard library when dealing with integers:
When I ran both, I got 3 milliseconds and 15 milliseconds printed for forLoopMillisElapsed and forEachMillisEllapsed respectively. So I set out to figure out what could possibly be the reason for the difference in performance.
IntelliJ IDEA lets you easily decompile Kotlin code into Java using Tools > Kotlin > Show Kotlin Bytecode > Decompile. Let’s decompile the two code blocks above and study the results:
The snippet with the for loop decompiled contains:
The snippet with the forEach loop decompiled contains:
Therefore, it’s logical to conclude that the forEach function in this particular case is slower than the regular for loop due to the overhead of the allocating an Iterator and Iterable objects when iterating over the array.
Because it is so easy to get basic code performance measurements with Kotlin, I anticipate using measureTimeMillis in my code quite a bit going forward. That, along with studying the decompiled Kotlin byte code, is a great way to gain an insight into how Kotlin interacts with the JVM. Will the resulting code always be optimal? Not necessarily — there are always tradeoffs between code performance, clarity and conciseness. But that is a topic for another article.
Create your free account to unlock your custom reading experience.