Kotlin vs Java: What Software Engineers Choose for Android Development


22 min read

On May 2019, Google announced Kotlin a preferred language for Android development. Every industry has a topic to “holy-war” about. Competition between Kotlin and Java used to be a stumbling point of Android development. Now it is Kotlin-first approach. Despite the fact that Kotlin and Java are not competitors anymore, developers and business projects still have reasons to use Java and need some time, knowledge, and effort to switch. What are the advantages of Kotlin or where Java still rules in developing a mobile app and digital business assets? Why is Kotlin better for Android development? How long does it take for a developer to switch from Java to Kotlin? Is Kotlin advantageous enough to strain a Java developer’s muscles? This article is based on the real experience of an expert from our sci-tech team and contains fifteen pros of Kotlin compared to Java from the Android developer’s point of view, complemented with five benefits of a business app developing in Kotlin.

Why may an app developer switch from Java to Kotlin?

Java used to be the primary language of Android development from its inception. Until the day when it seemed that the rival language appeared. The day when Kotlin was introduced. Some say Kotlin is Android’s version of Swift, and others claim that it’s an ugly language with the lousy design. So is it that ugly? Luckily there is no programming language cliff, and it’s not Sparta here, so even if someone judges the language as ugly it still has the right to exist, doesn’t it? Kidding, Kotlin is not ugly. Just the opposite, Kotlin now is the first official language of Android development.

Imagine you have been an experienced Android developer writing code in Java for years. Could there be a reason for you to switch from Java to Kotlin, a new just-appeared language, which everyone is so excited about?

We all know how the tech world works:

  1. A new technology pops up.
  2. The whole community goes crazy about it, stating that this new-comer is the future, and we all MUST embrace it.
  3. However, in a year or two at the longest, things go back. A new and shiny technology disappears.
  4. Meanwhile, solid and reliable old methods, languages, and approaches stay and keep serving their purpose.

Kotlin turned out to move a bit different way from the usual trends. There are a bunch of reasons for its success and why app developer may benefit from switching from Java to Kotlin:

  • Kotlin code is compiled to Java bytecode (on JVM). It’s fully interoperable/compatible with Java, meaning that there is no need to change your existing code to start using Kotlin at all. The value for app developers is that they may switch between languages anytime at any stage of the mobile app development process, and, yet, save time on code compilation.
  • Kotlin provides a developer with everything Java does, plus more. It brings a wider variety of modern approaches to syntax and coding (though not all those methods are newly invented). Such flexibility of a programming language syntax helps app developers build complicated functionality easier and write fewer code lines.

The Dashdevs developers’ flashback:

When I saw Kotlin syntax for the first time, I was disappointed and tried to throw it out of my head. Though Java is verbose, I liked its syntax. In Java, to understand the code, you need just a glance, and you identify what is what and what for and ready to proceed. While the Kotlin syntax… Well, it didn’t impress me. There were no semicolons, which I felt was unsafe for some reason. It lacked explicit variable types here and there. And oh… By the way, in Kotlin, you need to put a type after the variable’s name. Also, you’re obliged to specify if it’s a variable or a value (final) by adding the explicit keyword: “fun” for methods and “constructor” for constructors… My experience in Java was just the opposite, and I didn’t understand why I might need such keywords? Moreover, it was announced that Kotlin solves nullability issues. So I tested the statement and saw that it’s not accurate. It’s still up to you as a developer, who still must handle everything yourself. No magic NPE disappearance had happened, obviously. And have we not use @Nullable and @NonNull annotations before, right, ah?

That was how I thought back then. The reality turned out to be a little different, though.

One of Dashdevs’ Android developers had to jump into the ongoing project written half in Java and half in Kotlin. As a Java developer, he joined when the development was in progress and lead the project up to its delivery and release.

That is what he remembers:

“I’m not the most eager learner (which is bad). So it would be painful for me to work on this hybrid. It was how I thought it would be until I started.”

In reality, an adaptation from Java to Kotlin went much easier. Android Studio (and Idea IDE) has a built-in tool for converting Java code to Kotlin and vice versa. By converting a couple of lines of code up and backward, the engineer grasped what Kotlin is and how it works. It took a Java developer less than a week to involve in Kotlin completely (and, as a side effect, — fall in love with it :D). It went out that Kotlin is an enjoyable language that addresses many Java developers’ pains. Also, it’s very easy to learn!

One of such issues with Java was a lack of a convenient way (though it is a controversial opinion) for passing a function as a parameter without creating additional interfaces, runnables, or some other workarounds.

Among the other pains to mention, of course, there were all of the countless “if (something != null)"’s (or missing one in the appropriate place), extensive verbosity, lack of smart casts, lack string templates… As soon as pains were solved a long time ago, now there is no need to remember all the issues that had been giving developers hard times. Moreover, we all tend to take good things for granted.

So what’s Kotlin for the app developer familiar with Java? Of course, it’s more than just that, but you can think of it as an enhancement layer on top of Java

Advantages of Kotlin for Android app development

Well, let’s delve into what pros Kotlin has offered us versus Java. This comparison is made in the context of Android development, so the Java version here can be considered as 8th or even 7th.

There is not a comprehensive list below, just a couple of prominent things to highlight.

1. Null Safety in Kotlin vs. Java

Dealing with an object in Java, a mobile app developer should be attentive. An object may hold a real value, or there may be a null as well. In Android development, the issue is usually solved by either making some assumptions here and there, by adding appropriate annotations or maybe by using Optionals. Nevertheless, since there is no means to prevent developers from making a mistake, sooner or later they make it.

In Kotlin, the type system identifies references that can hold null and those that can not. So if a mobile app engineer specifies that a field is non-nullable, and there won’t be any nulls. The difference between Java and Kotlin is in the syntax, in adding a question mark after a type: String vs. String?. So when you have a function with a non-nullable argument, you put it the following way:

fun actionWithNonNull (argument: String) {

An Android developer (as well as a compiler) is confident that the argument is never null, so there is no need for any additional checks.

However, if you specify an argument as a nullable type, it looks like the one below:

fun actionWithNullable (argument: String?) { ... }

In Kotlin, it means that there may be a null as an argument, so a developer needs to handle nullability. The solution is similar to @Nonnull and @Nullable annotations, but the difference is that in Kotlin the code won’t compile if an app developer does not handle nullability. An engineer also won’t be able to pass a null to actionWithNonNull() function.

Such an approach makes a mobile app developer keep the nullability in mind and recognize whether it is really required. Kotlin helps to get rid of unexpected nullability. In cases where nullability is required, Kotlin ensures complete awareness of possible nulls and provides more convenient ways of handling nullability-related issues.

Let’s say you have some repository that is nullable and you need to fetch some data using it. Below is a comparison of the same sample code in Java and Kotlin.

In Java, code may look like the following way:

public class Test {
    private Repository repository;

    private void displayRating() {
        if (repository != null) {
            User user = repository.fetchUser();
            if (user != null) {
                if (user.rating != null) {
                    Integer amountOfStars = user.rating.amountOfStars;

And below is how the same sample code may look in Kotlin:

class TestKotlin {
    private var repository: Repository? = null

    private fun doSomething() {
  val amountOfStars: Int? = repository?.fetchUser()?.rating?.amountOfStars
        val info: String = amountOfStars?.toString() ?: "Error"

As you can see, it looks a lot better in Kotlin. There is no nested if’s, no nothing. Of course, this is just a ridiculous example, but it reveals some perspective.

2. Fields and constructors in Kotlin compared to Java

Another important point to compare is the way Kotlin and Java work with fields and constructors.

Let’s say you have a couple of fields in your class with some accessors. As simple as the next in Java:

class User {
    private String firstName;
    private String lastName;

    User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;

    public String getFirstName() {
        return firstName;

    public void setFirstName(String firstName) {
        this.firstName = firstName;

    public String getLastName() {
        return lastName;

    public void setLastName(String lastName) {
        this.lastName = lastName;

Now let’s see how the same code looks like in Kotlin:

class User(var firstName: String, var lastName: String)

That’s it — the same functionality within a single line in Kotlin.

Moreover, if you add data at the beginning of the line and make it a data class:

data class User(var firstName: String, var lastName: String)

you’ll get equals(), hashCode() and toString() for free.

Also, if you need some custom setter/getter, you can have them, using Kotlin’s properties:

class GrandpaUser(grandpaName: String) {
    private var tellMeWhoToBeCounter = 0
    var name: String = grandpaName
        get() = "Ye olde $field"
        set(value) {
            field = value

If you need a private setter — you can have it as well:

var name: String = grandpaName
        get() = "Ye olde $field"
        private set(value) {
            field = value

However, if you need a public setter, and a private getter as well, then, unfortunately, you can’t do that in Kotlin ATM. You’ll need to write plain Java-style getters and setters.

3. Named parameters, default values in Kotlin

In mobile app development, sometimes you have a function that receives multiple arguments of the same type, and it can be quite error-prone:

fun createDetail(isAvailable: Boolean, isReliable: Boolean, isComposable: Boolean)

In such cases, to be certain of what you’re passing, you can use named parameters:

val detail = createDetail(
	isAvailable = false,
	isReliable = true,
	isComposable = false

An app developer can use the same approach to instantiate an object:

val detail = Detail(
	isAvailable = false,
	isReliable = true,
	isComposable = false

Moreover, there’s one cool thing a Java developer will certainly love in Kotlindefault values.

You don’t need to have multiple overloads of the function or a constructor if some arguments should not pass. There is a more elegant solution in Kotlin — just add a default value:

fun createUser(name: String, isSuperUser: Boolean = false, 
groupName: String = "default")
val newUser = createUser("John Doe")

In the given sample, there is a default value for isSuperUser and groupName arguments, so there is no need to pass them if we do not want to.

However, what if you want to specify groupName while omitting isSuperUser? You can do that too:

val newUser = createUser(name = "John Doe", groupName = "lucky")

Kotlin allows leveraging this and making an easy copy of the object with only tiny changes to it by using copy() function available for data classes:

   data class User(
       val firstName: String, 
       val lastName: String, 
       val group: String, 
       val bloodType: String

  val father = User("Butterscotch", "Horseman", "regular", "AB-")
  val son = father.copy(firstName = "Bojack")	

As a result, you get a son user with the changed first name “Bojack”, and everything else left the same. Doesn’t it seem quite convenient?

4. Lambdas and functions when writing in Kotlin instead of Java

Kotlin is a first-class language. It means that it is possible to store functions in variables and data structures, and pass functions as arguments to other higher-order functions and returned them back. Now let’s suppose there is a need to pass a lambda to a method. In Kotlin, lambdas are not declared functions, which are passed immediately as an expression. What app developers often do in Java for such cases is they create an interface with one method. In Kotlin, a developer doesn’t need to create anything, you just pass the lambda:

 fun callingFunction() {
    lambdaReceivingFunction { users ->
	    users.filter { it.age > 18 }.size

 fun lambdaReceivingFunction(action: (List) -> Int) {
    val users: List = repository.getUsers()
    val result = action(users)

Actually, developers can do much more with functions in Kotlin. There is an option to have functions outside of the classes, and even assign a function to a variable if required. Functions are objects in Kotlin, though a developer might not even pay much attention to it.

And, of course, developing a mobile app a software engineer can have an object containing a lambda as easy as the following:

val someLambda: (String) -> Int = { it.length }

So with all this being said here, you might be worried about memory allocation overhead. There’s a solution for that too: a developer can use inline functions. Basically, instead of creating a function object for the parameter and generating a call, the compiler will put the body of your function in place of its call.

Now let’s add an inline keyword to the mentioned above function:

inline fun lambdaReceivingFunction(action: (List) -> Int) {

And, we can call this function the same as before, YET after compilation, the caller function will logically look the following way:

fun callingFunction() {
    val users: List = repository.getUsers()
    val result = users.filter { it.age > 18 }.size

There are some limitations to this approach, but for most cases, an app developer can use it to reduce any overhead.

(Also, have you noticed that filter() function used in the example above? Kotlin provides tons of handy extensions for collections that a developer can use out of the box).

5. Extension functions in Kotlin

Since we’ve been talking about functions in mobile app development, it would be a crime to omit extension functions.

Let’s say a developer has to validate some string in Kotlin.

fun validate(String stringToCheck): Boolean {
    return stringToCheck.length > 0

 someString: String = someObject.someString
 isValid: Boolean = isStringValid(someString)

That’s fine. Yet, what if we create an extension function instead of our regular validate() one? A result can be much nicer! Here’s extension function on String class:

fun String.validate(): Boolean {
    return length > 0

And then a caller code changes to:

val isValid: Boolean = someObject.someString.validate()

It looks like validate() is a function of a String class, but it’s not, indeed. It was an app developer who wrote it, and it’s outside of the String class, obviously. Within an extension function, a developer can access public methods and fields of the class you’re extending by using this reference. Pretty neat, huh? Moreover, if a function would make more sense being a property, a developer can have an extension property too:

val String.isLongName: Boolean
    get() = length > 20

and then use it:

val isLongName: Boolean = someObject.someString.isLongName

6. Expression body functions in Kotlin

Wondering if one could make a mobile app code even more better-looking? If you code in Kotlin, there is definitely a way! Let’s say we have this regular function that combines first and last names:

fun combineNames(firstName: String, lastName: String): String {
	return "Mr/Mrs $firstName $lastName"

Since it is a single-line code, we can get rid of the return type (a compiler will automatically infer it) and omit a couple of other redundant things too, and now here’s how the result will look like:

fun combineNames(firstName: String, lastName: String) = 
"Mr/Mrs $firstName $lastName"

7. Singletons in Kotlin

This one is the shortest point. Need a simple singleton while developing a mobile application? In Kotlin, you’ve got one:

object Pony {
    fun prance() {

And then use it like this:


The Pony is (certainly!) initialized when Gandalf arrives it is accessed for the first time.

8. String templates in Kotlin

You might be well familiar with such a thing as a string template from multiple different languages for mobile application development. This string template may seem like a small thing, nevertheless convenient and powerful.

A developer has an option to replace string concatenations with prettier and more convenient string templates.:

val message = "User ${user.firstName} ${user.lastName} (${user.age})
wants to add you to $groupName"

Nice and easy!

9. Smart casts in Kotlin

Let’s suppose there is a class CoolUser that extends class User, and a developer wants to do something if a given user is cool:

In Java the code would look something like this:

if (user instanceof CoolUser) {
    ((CoolUser) user).doCoolThing();

While in Kotlin, thanks to smart casts, an app developer can do it the following way:

if (user is CoolUser) {

Or maybe you’d prefer a safe cast operator as?

(user as? CoolUser)?.doCoolThing()

As mentioned in the example, if a software engineer has performed a check once, the code below assumes check’s result automatically, and there is no need to cast explicitly.

10. “When” expressions in Kotlin vs. Java

So where smartcasts truly shine is when they are combined with when.

Imagine there is a couple of classes extending User: CoolUser, AngryUser, IndifferentUser, and each of those have methods specific to their types. Let’s say there is a need to perform different actions based on the user type. To do this in Java, a developer can use if/else. In Kotlin though, it can be handled a little more graciously:

when (user) {
	is CoolUser -> user.doCoolThing()
	is AngryUser -> user.doAngryThing()
	is IndifferentUser -> user.doIndifferentThing()

Isn’t that concise? Moreover, an app developer can do multiple checks:

when {
	(user is CoolUser) && (user.age > 18) -> // Do something...
	(user is IndifferentUser) || (user.age > 18) -> // Do something
	else -> // Do something else	

A software engineer can also use when as a statement and return a value:

val title = when (user) {
	is CoolUser, is Indifferent -> user.firstName
	else -> user.lastName

11. Differences of a protected modifier usage in Kotlin and Java

Have you, as an Android app developer, ever wondered why protected members of a class are package-visible in Java? Our experts certainly had. In Kotlin, as it is expected, a protected member is accessible only from within the class itself and from its subclasses. A little more secretiveness is in here, in Kotlin.

12. Asynchronous work in Kotlin versus Java

If you’re developing an Android app, there’s a 100% chance you’ll have to deal with asynchronous operations. A developer might use AsyncTasks, Loaders, Executors, Threads, or something else. There’s a good chance a developer won’t be happy about using any of the above. Kotlin allows using all those approaches too and offering another way of handling this sort of tasks: coroutines. Coroutines are essentially light-weight threads that let an app developer convert an asynchronous code to the one that looks synchronous. However, we won’t dig deeper in this article, as a coroutine is a topic which deserves a couple of articles. Below is an example just to give a glimpse of how a coroutine can look like.

fun displayPurchases() {
	launch(Main) { // launch coroutine on the main thread
		val purchases = withContext(IO) { // switch to IO thread
			// Fetch data:
			val user = repository.fetchUser() // long-running operation
			repository.fetchUserPurchases(user.id) // long-running operation
		displayPurchases(purchases) // display result on the main thread

The code within the launch { } is executed synchronously, so a developer doesn’t need callbacks or anything else. It works just like a regular code.

We start a coroutine on the main thread. Then we fetch data on the background thread (using withContext(IO) to switch thread). After all, we proceeded with the result of repository.fetchUserPurchases(user.id) being saved to purchases. After that, we display the purchases as we would normally do — back on the main thread.

In this case, we need a**user**’s id to fetch purchases, so we wait until a user is fetched. If in your case, you want to execute multiple calls in parallel, it can be done with the help of async/await. Let’s say there is a need to get 2 lists and then return them combined.

suspend fun getExpenses(): List =
	withContext(Dispatchers.IO) {
        val main = async { repository.getMainExpenses() }
        val additional = async { repository.getAdditionalExpenses() }
        return@withContext main.await() + additional.await()

(Yep, in Kotlin a mobile app developer can add 2 lists just like that, using the plus operator).

As you can see from the example, everything’s pretty easy and straightforward in Kotlin. No callbacks, nothing that is spread across multiple lines of code. A developer launches long-running operations that are executed in parallel, waits for them to finish and then returns results.

13. Delegates in Kotlin

Kotlin provides a developer with a set of default property delegates and allows to create custom ones.

There’s one delegate that might be crucial for mobile app development, which we would like to mention: lazy.

Let’s say there is a field an app developer might or might not need to access at some point. However, the object is heavy enough that it makes a developer think: do I need to instantiate it if there’s a chance that I won’t need it at all?

A developer can resolve this issue with the help of lazy delegate:

val errorHandler by lazy { ErrorHandler() }

Having errorHandler declared like in the example below, the object won’t be instantiated until it’s accessed for the first time. Another one Kotlin’s convenience popped up out of the box helpful for mobile app development, right?

And oh, it’s also possible to have implementation by the delegation in Kotlin. Please, refer to the sample below:

interface MyInterface

class SomeClass : MyInterface

class Other (val myInterfaceImplementation: SomeClass) : 
MyInterface by myInterfaceImplementation

It is time to highlight that a developer can have rather var (as in variable) or val (as in value, read-only one) variables. At first, it may seem annoying to specify it explicitly, but it improves code quite a bit.

Opposite to Kotlin, in Java, a developer could achieve the same result is by using the final keyword. However, Kotlin requires a software engineer to make more conscious decisions. Thus it is hard to forget to make a choice. Also, if a developer chooses wrong (e.g., makes it a var and then assigns value once), there will appear a lint hint telling a variable can be changed to val.

14. Collections in Kotlin

Just a couple of words hereabouts, because it’s quite a large topic.

So how would you like it if you could instantiate a list this way?

val myList = listOf("First", "Second", "Third")

or a map:

 val myMap = mutableMapOf(
    "First" to 1,
	"Second" to 2,
	"Third" to 3

and then use it like in the following example:

 val first = myMap["First"]

Or maybe a developer would like to remove items from the map the next way:

myMap -= "Third"

Alternatively, how would you like if you had mapping, zipping, associating, filtering, sorting, and many more other functions for collections out of the box?
Good news for Android developers — in Kotlin, you have it all.

15. Other Kotlin advantages compared to Java

Well ok, this list is already rather too long for a single article. It can be continued since Kotlin offers tons of useful stuff for mobile application development. Android-specific extensions had not even entered the list, although there are plenty of them in Kotlin and they are good.

Let’s look at the following case. If developers access Java’s getters/setters from Kotlin, they can access them as if they were properties. So if you have a Java class User, then in Kotlin, you can access it in one of the following ways:




And also



user.name = "NewName"

As you can see, such an approach does not only improves developers’ experience when working with code written in Kotlin but also when accessing your Java code as well.

Disadvantages of Kotlin for app development

Despite numerous advantages of Kotlin, there are still a couple of things an app developer might be missing if switching from Java to Kotlin.

1. No ternary operator (a ? b : c) in Kotlin

Yep, Kotlin doesn’t have it. Although a developer can make use of if/else statement to achieve results close to it: val user = if (oldUserIsValid) user else User(). However, it’s not the same.

2. No static members in Kotlin

Yeah, you’ve not misread it, there’s no such thing in Kotlin. But there’s a solution for that too: a developer can add a companion object.

Class User {
    companion object {
        fun staticFunction() {

And then call it the way a developer does with static methods:


3. No implicit widening conversion in Kotlin

If you’re used to this type of things in Java:

 int someInt = 0;	
 long someLong = someInt;

There is some bad news for you: it won’t compile in Kotlin. A developer will need to convert types explicitly:

 val someInt: Int = 0
 val long: Long = someInt.toLong()

Build speed and runtime allocation overhead in Kotlin vs. Java

There are some debates considering build speed and runtime allocation overhead. If you feel that it can be a bottleneck for your project, you might want to check these articles:

(Be aware that they did not use Gradle and did not use incremental builds for annotation processor (Kapt) for their research, so it affected build speed).

  • Additionally, you can check this article of a little less depth:


  • And a quite thorough research on Performance evaluation of Kotlin and Java on Android runtime:


In general, if you do not abuse language features and use Gradle daemon with the combination of incremental builds, the number of differences you will feel compared to Java build time will be next to none.

Benefits of Kotlin mobile app development for business

So is this it, are there any other cons? And also, isn’t everything mentioned above as “pros” just a bunch of syntactic sugar examples you can certainly live without? Well, it might seem like that, however, bear in mind — we’ve just scraped the surface with this article. Yet, those mentioned things united all together bring drastic changes in how Android developers write code and how they read it. Android development has become Kotlin-first today.

Five benefits a business may gain from developing apps in Kotlin:

  1. With Kotlin, your business app code is less verbose. The smaller codebase and more readable code mean saving developers time on this code processing, like onboarding and code reviews.
  2. The Kotlin code is written faster due to its developer-friendly structures, more elegant syntax, and your Android business app development time may be reduced. For example, the Hello World program code in Kotlin may be 51-characters long, while the same code consists of 116 characters in Java.
  3. In Kotlin, it is easier to write a code, as well as, due to addressing the main pains of app development and syntactical solutions. A business can develop a high-quality complicated app with fewer resources.
  4. The Kotlin code is safer and less error-prone. Business apps written in Kotlin can be more robust and save even more time and resources on the testing stage. Just scan through the listed above syntax solutions, which logic prevent app developers from making mistakes (e.g., null safety, named parameters, asynchronous work, delegates, and others.)
  5. Kotlin allows functionality for mobile apps that won’t land in Java due to the slow pace of new Java versions adoption in Android. Kotlin is a relatively young language, and it is a go-to language for Android development. Kotlin has excellent community support. It improves quite fast. Kotlin is developed by the company, which basically created the Android Studio’s backbone IDE. This language is used for Android development for at least 4 years. Kotlin has been supported by Google for around 3 years and has been a first-class citizen in Android development for around 2 years. If you open Android’s developers’ documentation, you’ll notice that there are 2 tabs on the example snippets: Kotlin and Java, in that exact order.
  6. Moreover, you can target JavaScript and use Kotlin for web development. Developers can use Kotlin DSL with Gradle. Also, there’s an experimental Kotlin Multiplatform which allows writing business logic shareable between different platforms.

There are no more hesitations whether Kotlin is worth checking or not — the answer is it definitely is. No doubt, people’s tastes differ, so one can be displeased with the new things the other is excited about. You may find out that Kotlin is not for you, but at least you will know it for sure being aware of what it is if you try developing apps in Kotlin. If you are a bit overwhelmed with Android only, you may try cross-platform app development, and, in this case, our article about React Native and Flutter may be helpful.

We’ll see how it goes for Kotlin app development in general, but in the world of Android, Kotlin is the first now.

Share article

Table of contents