Is Java dead?

Will Kotlin take over as the language for back-end applications?

João Paulo Gomes Software Engineer


If you are a Java developer or not, you have probably already heard about Kotlin being used as a back-end language. Maybe you are worried. Perhaps you are excited about it. Still, you need to make a decision.

I am here to help you answer whether Java is dead and if it is time to start learning Kotlin. So, I will give you an overview of Kotlin and why you should consider it or not as your next programming language.


What is Kotlin?

Kotlin is a modern programming language, statically typed, that can be compiled to JVM byte codes, JavaScript, or native code through LLVM. The focus of this article is the JVM-compiled Kotlin.

Why was Kotlin born?

The Kotlin programming language was created by JetBrains to be used in the development of the Intellij IDE simply because the team wanted a better language than Java to simplify the IDE source code.

Besides that, because they couldn’t just throw away all the existing Java code, the new language should be compatible with Java, running side by side in the same application, to facilitate the migration.

A little bit of history

In 2010 JetBrains started the development of the Kotlin language, and the version 1.0 was released after six years. In 2017, during the Google IO, Kotlin was announced as an official language for developing Android applications. One of the reasons for this change was the lawsuit from Oracle against Google for Java copyright violations.

The Java programming language is much older, it started to be created in 1991 at Sun Microsystems, and the version 1.0 was released in 1995. In 2009 Oracle bought Sun Microsystems and all its products, including Java, for 7 billion dollars.

Java was born with the objective of running the same code on any platform. Some years ago, the Java installer had this message that Java was running on billions of devices. It was possible because of the JVM, a group of tools capable of running Java byte codes on any device. The byte codes are an intermediary format that Java or Kotlin code is transformed before being compiled to native code by the JVM to that specific platform.

Curiosity: Origin of the names

The first name of the Java language was Oak, but they had to change it because another company was already using it. They say that the current name was suggested because of a coffee called Peet’s Java. Java is likely the coffee’s place of origin, an island in Indonesia.

Kotlin is also an island located in the Baltic Sea near Saint Petersburg. It was chosen because it’s an island name, like Java.

Kotlin compatibility with Java tools

Kotlin is compatible with the Java language, been possible to mix the two languages in the same project. In addition, most of the tools that Java developers use are also compatible with Kotlin.

For example, Spring and Micronaut frameworks offer official support to the Kotlin language. Those are two prominent and well-known frameworks in the Java community that already support Kotlin.

Another good example is Gradle. It is also compatible with Kotlin and allows you to write build scripts using Groovy and Kotlin. If you prefer Maven, there is also a plugin to compile Kotlin code.

Testing tools like Junit, Mockito, and Jacoco are also compatible with Kotlin. There is a dependency called Mockito Kotlin that adds auxiliary functions to write mocks more Kotlin idiomatic.

Interesting Kotlin features

I want to share with you some features I think are interesting in Kotlin. I will try to compare them with a similar Java feature when possible.

Declaring variables

In Kotlin, you can declare a variable in two ways: using var or using val. If you use thevar keyword, you will create a mutable variable like you are used to in Java.

Now comes the cool part from Kotlin. Do you remember when you wanted an immutable variable in Java?

            final string text = "Your constant string";

You don’t need that in Kotlin. You can use the keyword val to declare an immutable variable. The same as a final parameter in Java but with less code. Here is how it would look in Kotlin:

            val text = "Your constant string";

Type inference

Another cool thing from Kotlin is the type inference. The Kotlin compiler is smart enough to infer the type from a variable if it has enough information. Let’s take a look at the code below.

            val name = "John" // (1)
val price = 1.45 // (2)
val itens = 42 // (3)

fun findUser(id: Long): User {
    return User(id, "John")

val user = findUser(123) // (4)

We can see four type inference in the code above:

  1. When you assign something with double quotes to a variable, it will be of the type String.
  2. When you assign a number with decimal places, it will be a Double.
  3. When you assign a number without decimal places, it will be an Int.
  4. The function findUser returns an instance of User , and the compiler can infer the type.

This is nice because your code became less verbose. You don’t need to repeat yourself all the time. Since Java 10, it’s also possible to use type inference in local variables.

Null safety

Kotlin allows you to choose if a variable can be null or not. In Java, every non-primitive variable can be null. If you have already programmed in C#, you will find this very familiar. To make a variable nullable in Kotlin, you just need to add a question mark after the type. For example:

            val user: User? = null
val name: String? = null

And, if you need to accept null values, the language offers some resources like the Elvis Operator ?: to make it easier to work with nullables.

            fun greeting(name: String?): String {
    name ?: return "Hello everybody!"

    return "Hello ${name.toupper()}"

The Elvis Operator works like an if. If the value is null, it will execute the code after the Elvis Operator. If you use this operator, it’s not necessary to check if the value is null again because the compiler is smart enough to understand it. It only works if the variable is immutable.

Another interesting resource to work with nullables is the question mark to make safe calls. Using this operator, you can access a property or call a function of an object if it’s not null. Otherwise, it returns null. This way, you can avoid a null pointer exception.

            val name = user?.name

The example above is the same as:

            val name = if (user == null) { 
    } else {

Data class

How often did you need to create an object to carry data from one place to another? Data classes make this task easier. When you create a data class it already has some pre-baked methods: equals(), hashcode(), copy(), toString().

Besides that, you can define if its properties will be mutable or immutable. In Kotlin, you should give preference to immutable values. Here is an example:

            data class User(
    val name: String,
    val country: String

And if you need to update an immutable value, you can create a copy of the data class replacing the desired value:

            val userUpdated = user.copy(country = "Netherlands")

Since Java 14, we have a similar resource called Record.


What if you want to get just some properties from an object? In Kotlin, it’s possible! Kotlin allows you to destructure declarations to have easier access or to create a copy of variables. Here is an example of using destructuring in a data class in a simple way:

            val user = User("John", "Brazil")
val (name, country) = user


In Java, we can use IDE shortcuts or the Lombok project to reduce the amount of getters and setters we write. In Kotlin, there is a resource similar to one I have seen in the C# language. Let’s see it in action:

            class Cart {

    private val size = 0
    val isEmpty: Boolean
        get() = this.size == 0 // (1)
    var counter = 0
        set(value) { // (2)
            if (value >= 0)
                field = value

    private var _total = 0 // (3)
    var total: Int // (4)
        set(value) { _total = value } 
        get() = _total

fun main() {
    val cart = Cart()
    println(cart.isEmpty) // (5)
    cart.counter = 10 // (6)
  1. Property based on the value of another variable.
  2. Property that validates the input.
  3. Private field to store the property value.
  4. Complete property with getter and setter.
  5. Reading the value of a property.
  6. Assigning a value to a property.

You can also define the properties in the class constructor:

            class Product(
    val id: Long, // (1)
    var name: String, // (2)
    private val price: BigDecimal // (3)
  • The property was declared using the val keyword. This property has only a getter, and it’s immutable.
  • The property was declared using the var keyword. So it has a getter and a setter. It’s mutable.
  • The property was declared using private val, so it’s immutable and can only be accessed inside the class.

Smart cast

If you check the variable type in the following line, it will be cast.

            interface Person

class Driver : Person {
    fun working() = true

class Rider : Person {
    fun rating() = 5

fun main() {
    val person: Person = Driver()
    if (person is Driver) {
        println(person.working()) // (1)
  1. It’s allowed to invoke the working method because the variable type was checked in the previous line.

Single expression function

Sometimes we build one-line functions. In Kotlin, you can simplify this construction omitting the return type and the curly braces:

            fun isOdd(number: Int) = number % 2 == 0


Kotlin Coroutines are like threads, but lightweight. You can create much more coroutines than you can create threads. Look at this example extracted from the Kotlin website, it executes 100.000 coroutines in just 5 seconds:

            fun main() = runBlocking {
    repeat(100_000) { // launch a lot of coroutines
        launch {

The Java language uses the operating system threads. They are much more expensive when compared to coroutines. Another benefit of Coroutines, even using non-blocking multithread processing, your code is still executed in a sequential manner. You don’t need subscribers or callbacks.

            suspend fun doSomethingHeavy() {
  println("do work")

suspend fun main() {

The result will be:

            do work

The Java language has the Loom Project, this project brings virtual threads to the JVM, and the goal is to be better than the current threads.

Multiline string

You can write a multiline string in Kotlin using the triple-double quotes:

            val template = """
Hello [Name]! Welcome to [Company]

Thank you


Extension function

This is another familiar resource if you have already programmed using C#. The extension functions allow you to add methods in classes without access to the class’s source code. It helps to make your code more expressive.

            fun String.isPostCode() = Regex("^[0-9]{8}$").matches(this)

fun main() {
    val value = "09876587"

Named arguments

You can name the arguments in a function call. This way, you can change the order of the parameters:

            fun doSomething(name: String, city: String, state: String) {
    // do work

fun main() {
    doSomething(state = "SP", city = "Jundiaí", name = "John")

String interpolation

You can use variables in call functions inside a string using the $ as a prefix. To read a property of an object or call a function you also need to use curly braces:

            fun main() {
    val name = "John"    
    println("My name is $name, in uppercase is ${name.uppercase()}")

if/else and try/catch blocks return values

The last line of each block will be returned:

            fun main() {
    val isToday = true
    val message = if (isToday) {
        "Is today!"
    } else {
        "It is not today =/"

    val number: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }


Have you ever had to write something like this?

            if (i > 0 && i <= 4) {

You have to agree that sometimes those ifs can get hard to read. Kotlin has a nice way to handle this. In Kotlin, you can use ranges to make your code easier to understand and less verbose. For example, you can write the same if in this way:

            if (i in 1..4) {  

The range 1..4 is the same as 1 <= i && i <= 4.

You can also use the ranges in a for loop:

            for (i in 1..4) {  

To invert the order of the range, you can use the downTo operator:

            for (i in 4 downTo 1) {

You can also use the step operator if you don’t want to go one by one:

            for (i in 1..8 step 2) {

Function names can be sentences

This resource is interesting to write unit tests:

fun `Assert blog page title, content and status code`() {
    println(">> Assert blog page title, content and status code")
    val entity = restTemplate.getForEntity("/")


") }


As we can see, Kotlin has many exciting features to help us to write more readable and concise code. Besides that, we also can see that Kotlin works well with existing Java tools and frameworks. Does it mean that Kotlin is killing Java?

No, Java is not going to die because of the Kotlin language. Actually, the competition with Kotlin and other languages has been good for Java. In recent years, the Java language has evolved faster than before. Some news resources are being added in each new version, some of them similar to existing Kotlin resources.

One of the biggest accelerators of the growth of the Kotlin language was the adoption of Kotlin as an official language for developing Android applications. It happened in 2017, probably because Oracle’s lawsuit against Google accused it of infringing Java copyright laws. Besides that, the Kotlin language also has its merits. JetBrains was capable of creating a concise language that interoperates very well with the Java ecosystem.

Is it worth learning Kotlin? Absolutely! And if you are a Java developer, the learning curve tends to be small because you are already used to the tools. There are already a lot of big companies using the Kotlin language in their backend applications like Google, JetBrains, Zalando,, Rabobank, Itaú, Mercado Livre, etc.

This article is written by João Paulo Gomes, for the WAES Medium blog.