Choose Kotlin For Your Next Android Project

Android development continues to get more productive as we move forward and as some great software engineers step up to fill in the cracks that were left in the framework. Many of those improvements are built-on additions to the Java language: lambdas, try-with-resources, forEach, static and/or default methods in interfaces, etc.

Those changes in Java were inspired by (or outright copied from) modern features of other languages. Allow me to wet your whistle with some tasty information about why Kotlin is awesome. This is by no means a complete list of Kotlin’s amazing feature set; we’re just scratching the surface, so I encourage you to read more on your own and explore the language soon so you can make the decision to start using it in your project.

an extremely brief history of Kotlin (just the highest points):

And that basically brings us current time. Now in version 1.2, Kotlin continually improves and currently offers all the features you need and precious little of the boilerplate you abhor.

My reasons

Now, let me tell you why I think your next Android project should be created in Kotlin. I’d also like to share some other reasons that Kotlin is great to use as a language for Android development, in general.

null safety

As someone who has spent most of his career using Java, null safety is amazing, and I love it. I’ve pretty much forgotten how to write Java at this point.

Everything in Kotlin can be nullable or non-nullable. Non-nullable is the default. To make a type optional (nullable), append ? to it: e.g.- String?. An optional type is equivalent to a java type.

val optionalThing = providesOptionalThing()
optionalThing?.let {
    // this code is only executed when optionalThing is not null
    // you can refer to the non-null type as `it` in this block
    it.thingMethod()
}

This is a super simple example, and it could be replaced with a one-liner: optionalThing?.thingMethod(). When optionalThing is null in both examples thingMethod() won’t be executed and there won’t be a NullPointerException thrown!

As with all things, reflection might break some of these non-nullability rules, so be cautious when using values that comes out of some reflective code (I’m looking at you, Gson).

If you think you know better than the compile, you can assert yourself (and maybe invent some defects) by using the not-null assertion operator (double bang) !!. Double bang tells the compiler, “You might think this could be null, but it isn’t. Trust me, I’m a professional software developer, and I never write bugs.”

More information about null safety in on Kotlin’s web site.

static typing

Static typing reduces simple errors, makes them easier and faster to find, and overall makes your life easier. Even where the type of a value isn’t declared, the typing system ensures the type is clear and static. You can configure typing hints shown in Android Studio and IntelliJ by either right-clicking on a hint that is already being shown and then clicking “Show hints settings…” or by going to Preferences > Editor > General > Appearance > “Show parameter name hints” > Configure… and making sure that “Kotlin” is the selected language, then check “Options” at the bottom of the pane.

I was on the fence about hints at first, but I positively love them for making Kotlin easier. For example, they helped me start to gain an intuitive understanding of what the resulting type of an expression is going to be.

Type declarations are optional on properties and local variables, but they are mandatory on parameters and return types. So the type of str is quite clearly a String when declared like val str = "string value" and it is quite clearly ambiguous when declared like this val str = null even if you want it to be String?. The latter case requires specifying the type you want: i.e. – val str: String? = null.

variable type vs. value type

Value types make things much easier than Java where everything is a variable type. A declaration like val s = providesSomeStringValue() means that s won’t be changing through its scope. Once it attains a value, it cannot be changed (well, there is probably some reflection voodoo that can make it happen, but let’s not go there).

If we declared var s = providesSomeStringValue(), the value of s can be changed during its scope which could lead to potential defects and uncertainties that make development more difficult.

boilerplate elimination

Who likes boilerplate? I don’t see too many hands. Typical. Everyone is already browsing social media. We just got started here.

Here are a few ways Kotlin reduces boilerplate code wherever possible:

  • There is no new required to create an object.
  • There is no need to declare the type of a symbol when it is blatantly obvious.
  • Semicolons are not required at the end of a line.

To illustrate those three points, comparedvar ts = ThermoSiphon() with ThermoSiphon ts = new ThermoSiphon();. This reduction of boilerplate contributes to code readability and makes life sweeter.

Another great example of boilerplate assassination is Kotlin’s data class. For many data models, the Java classes all take the same basic form:

  • name
  • constructor(s)
  • private member variables
  • public accessors/modifiers
  • hashCode(), equals(), toString()

With Kotlin, most classes of this type can be just a single line of code:

data class Employee(val id: Int, val fistName: String, val lastName: String, val payRate: Double, val hireDate: Date)

That’s it. Getters/setters, hashCode(), equals(), and toString() are all synthesized behind the scenes. More information about data classes here.

extension functions

Extension functions are welcomed and immensely useful feature of the language. I’ve often written some sort of utility class to encapsulate things I need to do that are related to some other framework class. Extension functions make this so much easier. I still write utilities, but now they are in the form of files instead of classes, and the methods I create can be accessed directly from an instance of the class I’m concerning myself with.

Classic example: showing a toast. It’s a bit of a hassle to write the same code to show a toast day in and day out. Like almost everything else, we require a Context to get anything done. With Kotlin, we can easily create an extension function on commonly available implementations of Context to make our lives that much easier.

Here is how we could do that with an instance of Activity:

fun Activity.showShortToast(msg: String) {
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
}

That’s it. I prefer to create a file for extensions to keep it easy to maintain. I would put this one in a file like extensions/AndroidExtensions.kt. Do your thing, but don’t create more work for yourself than necessary by scattering extension functions all over your project — you or someone like you will hate you for it.

better function definitions

Functions, functions, functions. In Java-land, we called them methods, but Kotlin prefers functions. Having cut my teeth on imperative and procedural languages like Pascal, I refer to them as functions most of the time anyway, so it feels as comfortable as coming home to me.

Functions are declared; you may have noticed by now, with the fun keyword: fun myFunction() {}. And there we have an example of the minimum viable function in Kotlin. It’s quite nice to look at, don’t you think?

Functions just need a name, a list of parameters, and a body. Beautiful.

Remember all those times in Java when you wanted to have a method with a single name but multiple parameter lists? You know, for convenience. You had to write multiple methods with multiple signatures. Let’s abuse that Toast example some more:

void showToast(Context context, String message) { /* Always short toasts here */ }
void showToast(Context context, String message, int toastLength) { /* Now, the caller can specify the length if they like */ }

In this trivial example, I’ll leverage extension functions to reduce the number of parameters by one and then have the toastLength have a default value so that we have a single method signature that can be called multiple ways:

fun Activity.showToast(msg: String, toastLength: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, msg, toastLength).show()
}

// calling is easy ... assume we're in an activity now
showToast("oh hai")
...
showToast("nice, long hello", Toast.LENGTH_LONG)

The definition of Activity.showToast shows a function defined with a block body, but it could be one-lined by using Kotlin’s expression body syntax. Simple expressions can leverage this syntax by removing the braces:

fun Activity.showToast(msg: String, toastLength: Int = Toast.LENGTH_SHORT) = Toast.makeText(this, msg, toastLength).show()

By the way, simple expressions include things like if (notice the lack of the keyword return):

fun boolToInt(condition: Boolean): Int = if (condition) {
    1
} else {
    0
}

In cases when there’s a need to have multiple default parameters, you are not forced to specify each one in turn in order to just specify that fourth parameter that you’re really interested in making non-default. You can specify in your call which value you need to declare. Assume the following declaration:

fun someComplexFun(context: Context, msg: String = "default message", flags: Int = Context.MODE_PRIVATE, optionalBundle: Bundle? = null)

So now I want to call this method but I only want to specify the optionalBundle value (well and the always mandatory Context, amirite?). No problem:

someComplexFun(this, optionalBundle = thatBundleOverThere)

I can even specify one of the other parameters by name pretty much anywhere:

someComplexFun(this, optionalBundle = intent.extras, flags = 0)

Just don’t mix positional arguments with the named arguments. In this example, context is positional. It must always be first since it has no default value, and the others can be named in no required order.

There’s more information available on Kotlin’s website.

getters look like properties

Calling Android framework Java code from Kotlin is easy, and Kotlin makes it look more like Kotlin. For example, consider getting a reference to the parent Activity from inside a Fragment. You would have called getActivity() in Java, but in Kotlin you just reference the activity property.

This applies to setters as well, when they exist. TextView has getText() as well as setText(), of course. With Kotlin you can perform both actions with the text property of your TextView, or even better EditText:

// assume et is an EditText instance
if (et.text.toString().isEmpty()) { et.text = "Hello World" }

string interpolation is pretty cool

I have always hated assembling strings in Java. I prefer using StringBuilder to concatenation with the + operator on String (it’s the same thing ultimately, btw), but it’s verbose and a bit ugly. Kotlin makes it so much easier by adding string interpolation. For those not familiar with string interpolation, it works by allowing you to create a string in a more natural way — the compiler takes care of the StringBuilder ugliness behind the scenes when you create strings like this:

data class Employee(val id: Int, val name: String, val position: String, val hireDate: Date, val copierTrainingCompleted: Date?) {
    fun isCopierTrainingComplete(): Boolean = copierTrainingCompleted != null
}
...
val emp = getEmployee()
Log.d(TAG, "got employee: $emp")
// assume prior declaration of `fun java.util.Date.daysSince(date: Date): Int` for simplicity
Log.v(TAG, "employee has been on staff for ${emp.hireDate.daysSince(Date()) / 365.25f} years and has ${if (!emp.isCopierTrainingComplete()) "not " else ""}completed copier training")

operator overloading

I haven’t gotten a chance to make good use of operator overloading, but I know it is there for me when I need it. Kotlin lets you define how the standard operators in the language perform functions on your class. I can see how this could be useful if you were dealing with certain types of data or just a bit more convenient for some operations. Here is a contrived example where I’m frequently adding some kind of offset to a geographic location, and I don’t care about anything other than making some modification to the latitude and longitude of a Location object:

data class LocationOffset(val lat: Double, val long: Double = lat)
operator fun Location.plus(offset: LocationOffset): Location {
    val l = Location(this)
    l.latitude += offset.lat
    l.longitude += offset.long
    return l
}

When this code is used it might look something not completely unlike this contrivance:

val loc = Location("mock")
val offs = LocationOffset(5.0)
val newLoc = loc + offs

newLoc now represents the location that loc represented only its latitude and longitude have been incremented by 5.0, which is probably a useless operation, but I hope you get the idea here. We just defined an operator on the Location class, which we don’t control the source of, that allows us to easily create new Location objects. Notice that we defined the types of the operands and that they are not homogeneous. We could multiply a String and a List<Canvas> and have the result be Set<Date>. I’m just trying to illustrate how much power this provides to developers — I can’t imagine why it would ever make sense to write operator fun String.times(list: List<Canvas>): Set<Date>.

Per usual, more information here.

things are final and public by default

Classes and member fields are final and public by default. If you want them to be something else you will need to add the appropriate modifiers. This is probably how things should have been in Java to begin with, so thanks to the Kotlin team for essentially enforcing this best practice by having developers do the least amount of work possible to make it happen.

Java interop

Native Android development has been nearly 100% Java since the beginning of Android. So Java is not something we can just walk away from — not at this point anyway. Kotlin claims to be interoperable with Java and it works; I’ve seen it. It works the other way around, but as you are more likely to be required to call Java code from within your brand new Kotlin project I’m going to leave calling Kotlin from Java as an exercise for the reader, suffice it to say that it is not hard.

Here are a couple of aspects of Java interop that stand out to me.

There are no longer primitive types — those are mapped to Kotlin’s types:

  • int -> kotlin.Int
  • boolean -> kotlin.Boolean
  • etc.

Java’s boxed types are also mapped:

  • java.lang.Integer -> kotlin.Int?
  • java.lang.Boolean -> kotlin.Boolean?

There are a few places where this gets a little dicey. For example, passing an array to a Java method that takes Java’s version of varargs will almost always require the spread operator, * to modify on the caller’s side although the compiler will just as frequently give you an unpleasant warning about that. Consider this contrived example:

Some Java code:

public class MyJavaClass {
    static void myStaticMethod(int... someInts) {
        // something definitely happens with someInts
    }
}

Some Kotlin code that calls into some Java code:

val ints = intArrayOf(1, 2, 3)
MyJavaClass.myStaticMethod(*ints)

If I leave out the spread operator *, i.e. – MyJavaClass.myStaticMethod(ints), I get a somewhat confusing error message:

Type mismatch: inferred type is IntArray but Int was expected

And that’s unpleasant since, in Java, I can call the method like this MyJavaClass.myStaticMethod(new int[]{1, 2, 3}); and that’s just fine.

Additional information

I’ve decided to include a couple of additional tips here that cause me frustration because I typically can’t remember these things about the language yet, so I hope these help you as much as I hope it helps me to write them down.

elvis operator

The Elvis operator has a funny name but is quite useful. ?: allows developers to ensure a usable value ends up where it needs to be. Consider this code:

val needsToBeUsable = getNullableString() ?: "default value"

If the result of getNullableString() which is clearly of type String? turns out to be null, then the Elvis operator will ensure that the result of the expression ends up being "default value" instead of null. All the better if the result of getNullableString() is non-null — needsToBeUsable will have that value.

If you aren’t sure why it’s called the Elvis operator, pull up an image of the “King of Rock and Roll”, tilt your head to the left, squint your eyes really hard, and stare at the operator. See that ‘do? Unmistakeable.

java platform types

I wanted to take a moment and mention these single bangs you’ll see when overriding Java methods.

When a Java method parameter is not annotated as @Nullable or @NotNull in the parent class, its type appears in context-sensitive help with a single bang (SomeType!) which means you must decide if this is a nullable thing or not. The default is an optional type, but you are free to take matters into your own hands when you know that the method is never called with a null for the parameter and change the signature to a non-nullable type. Doing this means you are either right and you don’t need to null-safe that parameter or you are wrong and your code crashes.

scope disambiguation

When developing for Android in Java, I’ve frequently found the need to qualify the scope of a variable I’m referencing for the current instance of my Activity from an inner class or something of that nature. Most Java developers will be familiar with how this is accomplished in Java: MainActivity.this.startActivity(intent).

This is still possible in Kotlin, but the syntax takes a little getting used to: this@MainActivity.startActivity(intent)

TL; DR

Kotlin has a feature set that helps to make Android development faster and eliminate many common opportunities for defects. The overall result is more productive developers, more maintainable code, and fewer crashes in production. It’s kind of awesome.

Next steps

Ok, so what are you still doing here? I’m kidding — read all of our blog entries; they’re full of wonderful knowledge and will help you to live a full and enjoyable life. If you must go, however, you might want to play around with Kotlin and get ready to start your next Android project with it. Don’t forget: you can quickly and easily start using Kotlin in your existing Java-based Android projects. So, check out the Kotlin koans to start getting used to the language.

Say hello to your new mobile product team.

  • This field is for validation purposes and should be left unchanged.


0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *