Kotlin vs. Java: First Impressions Using Kotlin for a Commercial Android Project

by: | May 3, 2017

It can be exciting but also a little daunting for any programmer to jump from a language you’ve come to understand in great detail over years of practice into something totally new. Especially when it’s for a commercial project, and you know your code will eventually be put to the test by millions of users.

But that’s what happened recently when, along with our client’s internal development team, we made the decision to use Kotlin for a commercial Android project — instead of Java.
smart app mobile app analytics
In Android development circles, Kotlin is being compared to Java in the same way that Swift has been compared to Objective-C. Like Swift, Kotlin is simple, clean and removes a lot of the code bloat from Java. Kotlin also adds some needed features that Java doesn’t yet support in Android.

We’d heard great things about Kotlin since it arrived on the scene in 2011, but like many new languages, it took a few years to be ready for commercial use. We’d experimented with it for internal projects and during hackathons. But the true test came shortly after Kotlin 1.0 arrived in February 2016: With more than 300 commercial projects completed, we at ArcTouch made the commitment to use Kotlin on a client project for the first time.

Kotlin vs. Java and how they fit together

The learning curve for using Kotlin is pretty low: Any experienced Java developer can pick up Kotlin in a few hours. The official documentation from JetBrains, the developers behind Kotlin, is thorough and very well done. C# developers (myself included) will also feel at home working with Kotlin, since the two languages share some features.

For Android development, with Android Studio, there is very good tooling support, since Android Studio is a fork from IntelliJ, which was also built by JetBrains.

It also interoperates seamlessly with Java. You can use Kotlin and Java files in the same project, and they will work nicely together. Developers that are just learning Kotlin can feel comfortable using the language for isolated parts of the application to test the results.

Using Java libraries with Kotlin-based projects is straightforward, too: It just works. The reverse is also true: You can easily include any library written in Kotlin within Java code. Some libraries provide Kotlin extensions, which in most cases are wrappers on some of the public APIs in Kotlin idioms. One example is RxKotlin, built on top of RxJava, which makes it more Kotlin friendly.

Perhaps the most important advantage of Kotlin vs. Java is the feature set. Kotlin adds some important new capabilities for Android development projects that you can’t yet find in Java. Some of my favorite features include:

  • Null safety through nullable and non-nullable types, safe calls and safe casts
  • Extension functions
  • Higher-order functions / lambda expressions
  • Data classes
  • Immutability
  • Coroutines (added on Kotlin 1.1)
  • Type aliases (added on Kotlin 1.1)

Null safety

Kotlin eliminates most sources of null references by making all types non-nullable by default — meaning that the compiler won’t let you use a non-initialized, non-nullable variable. If you need a variable to hold a null value, you have to declare the type as nullable, adding a question mark after the type.

In code, it looks like this:

var nonNullable: String = "My string" // needs to be initialized
var nullable: String?

Whenever you need to access a nullable variable, the compiler will enforce a null-check before accessing the variable. This makes the code clearer by being explicit on what can and cannot be null and drastically reduces bugs, increasing code and product quality.

When accessing a nullable variable, you can check if it’s null in two ways. The first is a traditional if statement:

if (nullable != null) nullable.doStuff()

The second is the safe call operator:

nullable?.doStuff()

The safe call operator can be chained multiple times, making navigating the properties of a nullable object with other nullable objects much more concise than multiple null checks.

Below you can see the usage of a non-nullable variable vs. a nullable variable with a safe call operator:

println(nonNullable.substring(0, 2)) // prints the first 2 characters

println(nullable?.substring(0, 2)) // prints the first 2 characters if the string is not null, prints null otherwise

There may be some cases where a variable is nullable, but you, as a programmer, are sure that the variable can’t be null. For such cases, the !! operator makes an unsafe call to a nullable variable, assuming it holds a value. If it’s null, a NullPointerException will be thrown.

println(nullable!!.substring(0,2)) // prints the first 2 characters if the string is not null, crashes with a NullPointerException otherwise.

Extension functions

Coming from C#, extension functions is a great feature — and another that’s currently missing in Java. With Kotlin, you can add behavior to a class without directly extending it or using a design pattern like Decorator. Through an extension function, you can call a function from an object as if it were part of its class. We could create an extension function for String called makePretty, and call it myString.makePretty(). As we know, makePretty is not a member of String, but syntactically it looks like it is. So, how does it work? You just need to add the function to any file. In our makePretty example, it would look something like this:

StringExtensions.kt

fun String.makePretty(): String {
    // … make the string pretty and return it
}

The key in the example above is the type qualifier before the function name. In Kotlin, it is compiled to a static function with a String parameter that returns a string. That way you could call this function from Java like StringExtensions.makePretty(myString);, whereas in Kotlin, you’d call it as if it were a member function, like myString.makePretty().

Higher-order functions and lambdas

One of Kotlin’s main features is higher-order functions. If you’re familiar with JavaScript (or C# and many others), you probably already know all about these functions. A higher-order function takes functions as parameters, or returns a function. One major use case for this is callback functions. We can create a function that makes a network call with two callbacks: one for success and another for error. In Kotlin, those would be two parameter functions, whereas in Java we would have to follow the pattern of having an interface, and pass an instance that implements that interface— which requires much more code. Functions can be stored in variables for later use, passed around, or created inside another function. If a function is not declared, but passed immediately as an expression, we call it a lambda, or an anonymous function. It is also called a “function literal.” Java 8 added support for lambdas, but if you’re developing for Android, you’re stuck with Java 7. This is one big reason why Kotlin is a great alternative to Java on Android.

Here is a comparison of how we would write a callback in Kotlin vs. Java.

In Kotlin:

fun networkCall(onSuccess: (ResultType) -> Unit, 
  onError: (Throwable) -> Unit) {
    try {
        // … create and execute network request
        onSuccess(myResult)
    } catch(e: Throwable) {
        onError(e)
    }
}

Usage:

networkCall(result -> {
    // use successful result
}, error -> {
    // handle error
});

In Java:

public interface Callback {
    void onSuccess(ResultType result);
    void onError(Exception exception);
}

public void networkCall(Callback callback) {
    try {
        // … create and execute network request
        callback.onSuccess(myResult);
    } catch(e: Throwable) {
        callback.onError(e);
    }
}

Usage:

networkCall(new Callback() {
    public void onSuccess(ResultType result) {
        // use successful result
    }
    public void onError(Exception exception) {
        // handle error
    }
});

Data classes

This feature is a great time saver. Given that most of our applications are data driven, we often find ourselves creating classes with only properties and fields to hold data. In Java, this can be very tedious, requiring a get/set method for each field. With Kotlin, we can declare the class and all its properties in a single line. The compiler will generate all getters and setters, as well as the equality members, toString() and a copy() function.

For example, take this in Java:

public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    public String getName() {
        return this.name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return this.age;
    }

    // and the methods equals, hashCode, copy, omitted for brevity
}

To run the same function in Kotlin, all we need is:

data class User(var name: String, var age: Int)

The compiler will generate everything we had to manually write in the above Java code.

Immutability

One big concern developers need to have when developing multithreaded applications is state management. If a variable is mutable, it can be changed by any thread that can access it. This means that if the data might be changed by multiple sources, you need to manually implement synchronization, which avoids data corruption but increases code complexity and execution time. If the data can never be changed, it can be accessed by multiple threads without error, since the data is immutable.

In Kotlin, you can declare variables with the keywords var and val. The former declares a variable that can be reassigned; the latter a variable that once assigned can never change. This gives the developer and the compiler confidence that the variable cannot be reassigned. Java has similar functionality with the final keyword, but the var/val keywords carry more meaning. When used to declare properties, var defines one with a getter and setter, whereas val defines a property with a getter and a private setter, and it must be assigned in the constructor.

This is not true immutability. If you have a val variable holding a mutable object, say an ArrayList, the contents of the list can be changed, even though you cannot assign a new list to the same variable directly.

Of note, the Kotlin standard library includes a number of immutable collection interfaces and utility functions to help you write immutable code. For example, the function listOf() creates an empty read-only list, which under the hood is a simple ArrayList. This has a disadvantage that to change the collection one can simply cast to ArrayList, but using a standard Java collection under the hood guarantees interoperability with Java.

Also it’s worth noting that traditional synchronization methods are still required for mutable data. So, if you’re creating a data source that can be changed by multiple threads, it is still required to ensure data consistency using lock statements.

Coroutines

In Kotlin 1.1, a new feature was added to the language: coroutines. Typically, when developers need to perform a long-running task such as a network operation or loading a file from disk, the calling thread gets blocked waiting for the operation to complete. Coroutines enable us to execute those types of operation without blocking a thread. Instead, it is a lighter operation called suspension of a coroutine. We can write seemingly synchronous code that is in fact asynchronous and during compilation the code will be transformed to be asynchronous. This means that this technique does not rely on the underlying virtual machine or operating system.

Type aliases

Also added in Kotlin 1.1, type aliases are a simple, yet very useful feature which will save you some keystrokes and make the code more readable. It basically is the ability to assign an alternative name, or alias, to any given type. This is most useful for long types with many generic parameters.

Example:

typealias MapOfLists = Map<String, List>

fun useMap(map: MapOfLists) {
    // ...
}

Kotlin and RxJava

If you’re working in Android development, there is a good chance you have worked with RxJava. Kotlin works well with RxJava, as it would with any Java library. But what makes RxJava a great fit with Kotlin is that both bring functional programming features into an imperative programming environment. They both have functions to filter and transform data, with RxJava acting on reactive streams of data and Kotlin on collections (for instance map() and filter()). Also, RxJava relies heavily on callbacks, something that Kotlin handles very well, as we’ve seen above. You can also use RxKotlin, which is built on top of RxJava and adds some extension functions to leverage Kotlin’s features.

Disadvantages over Java

While Kotlin improves in many ways over Java, developing with Kotlin for Android presents some challenges, though every new release is helping address some of these barriers. Most problematic: An app built with Kotlin will likely result in a larger file package size than one built purely in Java. That’s because Kotlin has its own standard library that’s added on top of Java’s standard library. Also, the build time for Kotlin is a little slower using Gradle, which can be frustrating. Though Gradle is also slow using only Java, it’s not quite as slow as with Kotlin.

Taking the leap

When I first started toying with Kotlin a few years ago, it wasn’t as mature and popular as it is today. As the language developed, it took some time for us to feel comfortable using it in a production code environment — and ultimately run it on millions of devices. But after completing this first commercial project, it’s clear that the decision to take that leap with Kotlin was the correct one. The language, and our code, turned out to be as advertised: concise, clear and correct. Kotlin helped us avoid some common pitfalls with Java, like null references, which increased product quality and our productivity, too. We’ve experienced many Kotlin updates during development, and every update was a smooth process. Using Java libraries with Kotlin was seamless as well, as expected.

At ArcTouch, we are sold on Kotlin. It was such a positive experience that it’s hard to imagine using any other language for native Android projects.


Thinking of using Kotlin for your next Android project?

We’re happy to help — from offering up advice to estimating what it would take.

Let’s Talk