As Kotlin approaching it's official 1.0 release, chances you heard about this fun language is very high. Kotlin offers an opportunity to improve our codes readability. Easy to try, relatively fast learning curve, and 100% interoperable with Java.
Wait, it's not version 1 yet, but you already started using it?
In last November, we released our Backlog Android 1.2 written in Kotlin. This release marks the first use of Kotlin language in our product.
Grab the app from Play Store.
Since it's M12 (Milestone 12), Kotlin started to catch our interest. 100% interoperable with Java is the safety net for us when trying Kotlin. This makes the cost to port our Backlog Android app from Java to Kotlin is 0 Yen (well, sort of. We have free coffee here 😛 ).
Our first Kotlin codes was compiled against Kotlin M12 and later we released the app compiled against Kotlin 1.0.0-Beta2.
We experienced both 'Joy' and 'Sad' moments along the porting process. Most of the time upgrading the Kotlin version and it's Android Studio library to the newer one simplifies our life. Only one or two upgrades sometimes caused extra works to make the app works again.
Let's start the fun
Adding support
One lazy way to add Kotlin support to existing Android project in Android Studio is by creating a Kotlin class to trigger project re-configuration as a Kotlin project in Android Studio, just follow the instruction at the screen. And welcome to the Kotlin world.
Depend on the nature of our project. We can port our Java codes using Code -> Convert Java File to Kotlin File menu, provided by Kotlin plugin for Android Studio, then adjust the result as necessary. Or create new Kotlin classes from scratch.
More methods in our Java codes means more funs we have.
Yes, in Kotlin the method(function) syntax start with fun.
From our Java class below
1 2 3 4 |
class MyClass { void myMethod() { } } |
And it's Kotlin counterpart
1 2 3 4 |
class MyClass { fun myMethod(){ } } |
Fun things from Kotlin
Here are some Kotlin features that we are using
Null safety
In Kotlin, the type system distinguishes between references that can hold null (nullable references) and those that can not (non-null references). This helps us to reduce NullPointerException in our code paths. Another advantage is the codes meanings are easier to understand.
1 2 |
// 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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; } } |
Can be converted to this Kotlin counterpart.
1 |
data class Customer(var name: String, var company: String) |
Multiple constructor
We are using this feature, together with two other features(default arguments and JvmOverloads annotation) in our custom View classes.
Our Java custom view can be read easily
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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); } } |
in Kotlin
1 2 3 4 |
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 function.
For example
1 2 3 4 5 6 |
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { doSomething(); } }); |
Can be expressed with less codes using Kotlin function literal, like below:
1 |
button.setOnClickListener { doSomething() } |
Extension functions
Usually we have codes dealing with app compatibility in several places. We could improve this situation using 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 3rd party library without modifying it's source codes.
For example, instead of doing API level checking every time we call append function. We create appendSpecial extension.
1 2 3 4 5 6 7 8 9 |
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
As in the current state, one disadvantage(or advantage 😛 ) using Kotlin is the compile time is longer than Java. Sometime full rebuild is needed when something went wrong.
Image via xkcd.com
Java interoperability
Event though we have released the app. It's still not 100% written in Kotlin yet. Small portion of Java classes still exist. The Java interoperability feature helps us in porting our Java codes step by step without disturbing our workflow.
Kotlin gives many appealing features to improve our code base more than what is written here.
Conclusion
Kotlin is easy to try and not hard to learn. In it's current state, Kotlin is already usable for our case even though not perfect. Compile time is longer compared to Java.
You can try it now, and remember if you have problem. Keep Calm.