From Java to Kotlin with lots of fun

From Java to Kotlin with lots of fun

Even though Kotlin is just approaching its official 1.0 release, chances are you’ve already heard about this fun language. Kotlin is a great way to improve your code’s readability. It’s also easy to try, relatively fast to learn, and 100% interoperable with Java.

When & why we started using Kotlin

Last November, we released Backlog Android 1.2 — our first use of Kotlin language with our products.

We’ve been interested in trying Kotlin ever since their M12 (Milestone 12). And because it is 100% interoperable with Java, we knew it was safe to experiment with. The cost to port our Backlog Android app from Java to Kotlin was practically nothing, aside from the coffee we drank during the process.

So we compiled our first code against Kotlin M12 and then later released the app on Kotlin 1.0.0-Beta2.

The porting process was straightforward, and the upgrading our version and it’s Android Studio library only simplified our lives. Only one or two upgrades gave us minor headaches, but it was overall worth it.

Getting started with Kotlin

Adding support

An easy way to add support for Kotlin to an existing Android project is by creating a Kotlin class to trigger project re-configuration as a Kotlin project in Android Studio. You just follow the instructions on the screen, and you’re done.

But this may not be ideal depending on the nature of your project. Alternatively, you can port your Java code by selecting Code > Convert Java File to Kotlin File from the menu of your Kotlin plugin for Android Studio, and then adjust the results as needed.

Finally, you can create new Kotlin classes from scratch.

In Kotlin, the method(function) syntax starts with fun.

From our Java class below

class MyClass {
  void myMethod() {
  }
}

And it’s Kotlin counterpart

class MyClass {
  fun myMethod(){
  }
}

Fun things from Kotlin

Here are some of our favorite features.

Null safety

The type system distinguishes between references that can hold null (nullable references) and those that can not (non-null references). This helps us reduce NullPointerException in our code paths.

We also find the code easier to understand.

// We can understand later as somewhere that alphabet can be null
var alphabet: String? = "abc"

Data class

We use data class to replace our POJO classes.

For example our Customer POJO in Java was this:

class Customer {
  private String name;
  private String company;

  public String getName() {
    return name;
  }

  public String setName(String name) {
    this.name = name;
  }

  public String getCompany() {
    return company;
  }

  public String setCompany(String company) {
    this.company = company;
  }
}

But it can be converted to this in Kotlin:

data class Customer(var name: String, var company: String)

Multiple constructor

We use this feature together with two other features (default arguments and JvmOverloads annotation) in our custom View classes.

In Java we use:

public class MyView extends View {
  public MyView(Context context) {
    super(context);
  }

  public MyView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }
}

But in Kotlin:

class MyView : View {
  @JvmOverloads public constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
  : super(context, attrs, defStyleAttr) {
}

Function literals (lambda expression)

We take advantage of this feature and automatic SAM conversion when dealing with many Android event listener functions.

For example

button.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    doSomething();
  }
});

This can be expressed with less code using the Kotlin function literal, like below:

button.setOnClickListener { doSomething() }

Extension functions

Usually, we have code dealing with app compatibility in several places. But now we can just use the extension function feature.

Kotlin provides the ability to extend a class with new functionality without having to inherit from the class. This is useful when we are using a 3rd party library without modifying it’s source code.

For example, instead of doing API level checking every time we call the append function, we can just create an appendSpecial extension.

fun SpannableStringBuilder.appendSpecial(text: CharSequence, what: Any, flags: Int) {
  if (Build.VERSION.SDK_INT >= 21) {
    append(text, what, flags)
  } else {
    val start = length
    append(text)
    setSpan(what, start, length, flags)
  }
}

More time to play

One disadvantage (or advantage) of using Kotlin is that the compile-time is longer than Java. Sometimes you have to do a full rebuild if something goes wrong.

Image via xkcd.com

 

Conclusion

Our app is still not 100% written in Kotlin, yet. Small portions of Java classes still exist. And Kotlin has many appealing features, more than we can cover in entirety here. Luckily, it’s easy to try, easy to learn, and available now.

Just remember: if anything goes wrong: Keep calm and drink coffee.

Screen Shot 2015-12-17 at 10.23.02 AM

Reza Reza is a member of Nulab, the creators of Backlog.