## DEV Community

Jean-Michel (jmfayard.dev)

Posted on • Updated on • Originally published at jmfayard.dev

# From Java to Kotlin in 20 minutes ⚡️

What is the experience like as a Java developer to start programming in Kotlin?

I didn't remember, it was years ago for me!

Fortunately a mob-programming session with my colleagues gave me the chance to see again things with a beginner's mind.

Story time!

## Show me the code!

To follow along, checkout the code.

You need to have IntelliJ Community Edition installed. It's free!

On MacOS for example, that's `\$ brew install intellij-idea-ce`

The code is here, and you can see all the changes described below in this pull-request

# Kata: the observed PIN

https://www.codewars.com/kata/5263c6999e0f40dee200059d/train/java

Alright, detective, one of our colleagues successfully observed our target person, Robby the robber. We followed him to a secret warehouse, where we assume to find all the stolen stuff. The door to this warehouse is secured by an electronic combination lock. Unfortunately our spy isn't sure about the PIN he saw, when Robby entered it.

The keypad has the following layout:

``````┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┼───┼───┘
│ 0 │
└───┘
``````

He noted the PIN 1357, but he also said, it is possible that each of the digits he saw could actually be another adjacent digit (horizontally or vertically, but not diagonally). E.g. instead of the 1 it could also be the 2 or 4. And instead of the 5 it could also be the…

But first some context

## Mob-programming

My colleagues Sarah and Peter and I were doing in a session of Mob programming

The goal was to solve the kata of The observed PIN, where an unreliable spy tells that he saw the PIN 1357 being used, but actually, he's not quite sure, each digit could be instead one of its neighbor on the keyboard layout. It could be 1357 but also for example 2357 or 1368.

The project was a Java project built with Maven. It contains two files: `PinGuesser.java` and `PinGuesserTest.java`. It compiles and run the unit tests in a matter of seconds, not minutes like in many Android apps. That makes for a better developer experience IMHO.

We were using IntelliJ's Code With Me to share the code.

We were doing well and had solved the Kata in Java, then had refactored it to a satisfactory state.

• Sarah : Is there anything else we could improve?
• Peter : I don't know, looks good to me.
• Me : Well, we have 20 minutes left, why not rewriting the whole thing in Kotlin?
• Sarah : Oh, I've heard about Kotlin but haven't had the chance to use it yet. 20 minutes though, do you think we can do it?
• Me : Let's get started and see where it leads us!

## `Tools > Kotlin > Configure Kotlin in project`

• Peter : Ok, so I have never done any Kotlin in my life, tell me what to do.
• Me : There is a command IntelliJ called `Convert Java File to Kotlin File`. It's a great starting point!
• Peter : Let's give it a try.

• Peter : IntelliJ tells me that Kotlin is not configured, that makes sense.
• Peter : How do I configure Kotlin in Maven?
• Me : I don't know, I always used Gradle.
• Me : Just let IntelliJ do it!
• Me : By the way, what it will do is the same thing as `Tools > Kotlin > Configure Kotlin in project`
• Peter : Let's do it
• Peter : It seems to have worked. There are updates to the file `pom.xml`
• Peter : first commit

## Tell Java that `@ParametersAreNonnullByDefault`

• Me : Before we try the Java to Kotlin converter, there is something we want to take are of.
• Me : As you know, Kotlin has integrated nullability in the type system while Java by default has not.
• Me : Therefore the converter is going to allow nulls everywhere, which is technically correct but not what you want.
• Sarah : But there are annotations in Java to say if something is nullable or not, right?
• Me : Exactly! And the one we want is to tell by default everything is non-null. Conveniently, it's exactly how it works in Kotlin too.
``````diff --git a/pom.xml b/pom.xml
<dependencies>
+        <dependency>
+            <artifactId>jsr305</artifactId>
+            <version>3.0.2</version>
+        </dependency>

+++ b/src/main/java/pin/package-info.java
@@ -0,0 +1,4 @@
+@ParametersAreNonnullByDefault
+package pin;
+
+import javax.annotation.ParametersAreNonnullByDefault;
``````

## PinGuesser: `Convert Java File to Kotlin File`

• Peter : I guess I now open `PinGuesser.java` and just relaunch the converter `Convert Java File to Kotlin File`
• Me : Correct
• Peter : It seems that... it worked? There is a file `PinGuesser.kt`
• Me : How do you know it worked, though?
• Sarah : You should run the unit tests
• Peter : Right

• Peter : It's still all green. Amazing, I have written my first Kotlin code ever, and it is bug-free!
• Sarah : Good job!
• Peter : What about the tests? Shouldn't we convert those too?
• Me : You don't need to. Java and Kotlin can co-exist peacefully in the same codebase.
• Sarah : Ok, but it looks fun, I want to try it out too!
• Peter : First let me commit

## PinGuesserTest: `Convert Java File to Kotlin File` and manual fixes

• Sarah : So I open `PinGuesserTest.java` and run the command. How is it called?
• Peter : `Convert Java File to Kotlin File`
• Sarah : Let's go!
• Sarah : I now have a `PinGuesserTest.kt` . It has some errors though

• Peter : Maybe apply the suggestion to optimize imports?
• Sarah : Ok.
• Sarah : It worked.
• Me : as you see it's not perfect, but it's an awesome learning tool: you start with what you already know (in Java) and see it converted in what you want to learn (in Kotlin)
• Sarah : Let me run the unit tests
• Sarah : I have some weird JUnit errors

• Me : Ok, so I understand that. Java has static methods while Kotlin has the concept of a companion object { ... }
• Me : Its methods look like static methods but are a bit different. Here JUnit really wants static methods, and we need an annotation to make it happy
``````-        fun testSingleDigitParameters(): Stream<Arguments> {
+        @JvmStatic fun testSingleDigitParameters(): Stream<Arguments> {
return Stream.of(
Arguments.of("1", java.util.Set.of("1", "2", "4")),
Arguments.of("2", java.util.Set.of("1", "2", "3", "5")),
@@ -61,7 +58,7 @@ internal class PinGuesserTest {
)
}

-        fun invalidParams(): Stream<Arguments> {
+        @JvmStatic  fun invalidParams(): Stream<Arguments> {
return Stream.of(
Arguments.of("   "),
Arguments.of("A"),
``````
• Sarah : Unit tests now work!
• Sarah : The project is now 100% in Kotlin
• Sarah : commit

## Use the Kotlin standard library

• Peter : What comes next?
• Me : It's possible to create `List`, `Set` and `Map` the traditional Java way, but the Kotlin standard library contains plenty of small utilities to streamline that, that would be my first change. Let me do it:

• Me : that looks better. Are the unit tests still green?
• Me : They are, let's commit

## Replace stream() API with Kotlin stdlib

• Me : Something else contained in the Kotlin Standard Library are functions found in the functional programming languages like `.map()`, `.filter()`, `.flatmap()` and much more.
• Sarah : A bit like the Java Stream API that we are using?
• Me : Yes, like this but less verbose and more performant under the hood!
``````-    fun combineSolutions(pins1: Set<String>, pins2: Set<String>): Set<String> {
-        return pins1.stream()
-            .flatMap { pin1: String ->
-                pins2
-                    .stream()
-                    .map { pin2: String -> pin1 + pin2 }
-            .collect(Collectors.toSet())
-    }

+    fun combineSolutions(pins1: Set<String>, pins2: Set<String>): Set<String> =
+        pins1.flatMap { pin1 ->
+            pins2.map { pin2 ->
+                "\$pin1\$pin2"
+             }
+        }.toSet()
``````
• Sarah : Unit tests are still green.
• Sarah : commit

## Make val, not var

• Me : Next, in idiomatic Kotlin style, we tend to use `val property` instead of `var property` most of the time.
• Peter : What's the difference?
• Me : `val property` is read-only, it has no setter, it's like a `final field` in Java
• Peter : I see. So, I just change the var property with a val?
• Me : Pretty much so.
• Peter : Easy enough
• Peter : commit

## Fail fast

• Sarah : Is there an idiomatic way to validate the parameters of a function?
• Sarah : The PIN should be something like `7294` with all characters being digits
• Me : Yes, you use `require(condition) { "error message" }` for that
• Sarah : How would that look here?
``````fun getPINs(observedPin: String): Set<String> {
require(observedPin.all { it in '0'..'9' }) { "PIN \$observedPin is invalid" }
// rest goes here
}
``````
• Sarah : Thanks!
• Sarah : commit

## Functional style

• Sarah : What comes next?
• Me : I would like to liberate the functions
• Peter : What do you mean?
• Me : Look, we have this `PinGuesser` class, but what it is doing exactly?
• Me : It's doing nothing, it's a dumb namespace.
• Me : It's a noun that prevents us for accessing directly the verbs who are doing the real work.
• Me : One of my favorite programming language of all time is Execution in the kingdom of nouns by Steve Yegge.
• Sarah : I know that rant, pure genius!
• Sarah : How do we free up the verbs/functions?
• Me : We remove the class and use top-level functions
``````diff --git a/src/main/java/pin/PinGuesser.kt b/src/main/java/pin/PinGuesser.kt
index 17a20b3..38e457c 100644
--- a/src/main/java/pin/PinGuesser.kt
+++ b/src/main/java/pin/PinGuesser.kt
@@ -1,9 +1,5 @@
package pin

-import java.util.stream.Collectors
-
-class PinGuesser {
-    companion object {
val mapPins = mapOf(
"1" to setOf("1", "2", "4"),
"2" to setOf("1", "2", "3", "5"),
@@ -16,7 +12,6 @@ class PinGuesser {
"9" to setOf("6", "8", "9"),
"0" to setOf("0", "8"),
)
-    }

fun getPINs(observedPin: String): Set<String> {
for (c in observedPin.toCharArray()) {
@@ -38,5 +33,4 @@ class PinGuesser {
pins2.map { pin2 ->
"\$pin1\$pin2"
}
-        }.toSet()
-}

--- a/src/test/java/PinGuesserTest.kt
+++ b/src/test/java/PinGuesserTest.kt
class PinGuesserTest {
-    val pinGuesser = PinGuesser()

@ParameterizedTest
@MethodSource("testSingleDigitParameters")
fun testSingleDigit(observedPin: String?, expected: Set<String?>?) {
-        val actual = pinGuesser.getPINs(observedPin!!)
+        val actual = getPINs(observedPin!!)
Assertions.assertEquals(expected, actual)
}
``````

## List.fold()

• Peter : Can we go a step back? What does it bring us to make the code nicer like this? At the end of the day, the customer doesn't care.
• Me : Well, I don't know you, but often I don't really understand the code I'm supposed to work on. I tend to work hard to simplify it and at some point it fits in my head and the solution becomes obvious.
• Peter : What would it looks like here?
• Me : Now that the code is in a nice functional idiomatic Kotlin, I realize that the program can be solved using a single functional construct: List.fold()
• Sarah : Show me the code
• Me : commit
``````fun getPINs(observedPin: String): Set<String> {
require(observedPin.all { it in mapPins }) { "PIN \$observedPin is invalid" }

return  observedPin.fold(initial = setOf("")) { acc: Set<String>, c: Char ->
val pinsForChar: Set<String> = mapPins[c]!!
combineSolutions(acc, pinsForChar)
}
}

fun combineSolutions(pins1: Set<String>, pins2: Set<String>): Set<String> =
pins1.flatMap { pin1 ->
pins2.map { pin2 ->
"\$pin1\$pin2"
}
}.toSet()
``````

## Where do We Go From Here?

If you want to get in touch, you are welcome to do so via https://jmfayard.dev/

The code is available at https://github.com/jmfayard/from-java-to-kotlin

Start in the `java` branch and compare with what is the `kotlin` branch. See this pull-request

Amazing explanation on how to convert legacy java projects to kotlin. I have in past converted small spring project into kotlin using intelliJ and have followed most of steps similar to your approach, But now I have a better understanding of sequence of steps I should have taken. Thank you for all the link to commits too. I wouldn't have understand few stuffs if you hadn't provided that.

I also thank you for link to Stevey's article. I enjoyed reading it too.

Can you explain a bit more about List.fold(), I read kotlin documentation on it and then tried going through that commit but have no clue what happened there. There were so many checks in before code, how are they handled by `fold()`, Its trippy.

Jean-Michel (jmfayard.dev) • Edited

Fold() can be used for example to reimplement the sum of elements in a list. You give it an initial value (0), and a function that you apply to an accumulator (your sum so far) and each next element

``````fun main() {
val ints = listOf(1, 4, 6, 8, 13)
val sum = ints.fold(0) { sum, elem -> sum + elem }
println(sum) // 32
}
``````

Before we treated what happened if you had 0, 1 or more than 1 element. Instead we could handle the case with 0 elements or more than 0. Next step was to use fold().

Abhinav Kulshreshtha

Ok, So `isEmpty` check is replaced by having an initial value as parameter of fold. case for 1 or more is handled by lambda. I think I understand it now. So those check-steps are not needed anymore.

`acc` will be initialized as empty setOf string because that is what is passed inside fold(), `c` will be current iterated value. and then you call `combineSolutions` with acc and mapPin of c.

Man lambdas are trippy.