fbpx

Kotlin 1.4 Features

1. Introduction

Kotlin programming language is becoming more and more popular nowadays. JetBrains team puts a lot of effort into improving the quality and performance of the language and its tooling. Indeed, the hard work pays off and Kotlin has been announced one of the top 5 most loved programming languages in the world (according to the StackOverflow Developer Survey 2020).

In this article, I would like to show you some of the features and changes introduced in the Kotlin 1.4 release.

2. New Compiler

Kotlin 1.4 brings a new compiler, which will unify all the supported platforms and provide the API for compiler extensions. At the moment, the JVM and JS IR backends are in the alpha stage, and once stabilized, they will be used by default. The new compiler brings also a new type inference algorithm enabled by default. This algorithm has been introduced in Kotlin 1.3, but we had to set the compiler option explicitly to use it. One of the most noticeable improvements are:

  • Java SAM interfaces in Kotlin
  • SAM conversion for Java interfaces with different arguments
  • More cases where type is inferred automatically
  • Smart casts for a lambda’s last expression
  • Smart casts for callable references
  • Better inference for delegated properties

If you would like to see the whole list of fixed issues, please visit this YouTrack.

3. SAM Conversions for Kotlin Interfaces

SAM (Single Abstract Method) interfaces, also known as functional interfaces, are interfaces with only one abstract method inside. SAM conversion, on the other hand, is the possibility to use a lambda expression instead of implementing the interface manually. Let’s see the following example:

fun interface MyInterface{
    fun returnString(): String
}

fun main() {
    val withoutSAM = object : MyInterface {
        override fun returnString() =
            "Example String"
    }

    val usingSAM = MyInterface { "Example String" }
}

As we can see, using SAM conversion allows us to create the instance of a class in a much cleaner manner.

Before Kotlin 1.4, this feature could be used only when working with Java methods and interfaces from Kotlin code. Now, we will have the possibility to use it with Kotlin interfaces as well. The only thing, we need to remember is to annotate the interface with a fun keyword.

4. Trailing Commas

The next cool feature, I would like to show is the possibility of adding trailing commas in enumerations, like arguments, or parameter lists, etc:

fun someMethod(
    one: String,
    two: Int, //trailing comma
) {}

val someList = listOf(
    "One",
    "Two",
)

With this pretty simple addon, we can easily manipulate the order of items, without the need for constant inserting and deleting commas.

5. Break and Continue Inside When In Loops

Before Kotlin 1.4 has been released, the only possibility to use the break or continue statement within the loop was the loop labeling:

some@for (x in 0..10) {
    when (x) {
        1 -> continue@some
        6 -> break@some
        else -> println(x)
    }
}

From now on, we do not have to do that anymore, which makes our code more readable:

for (x in 0..10) {
    when (x) {
        1 -> continue
        6 -> break
        else -> println(x)
    }
}

6. Additional Functions for Collections and Arrays

6.1. shuffled()

As the name indicates, this function shuffles the sequence:

val range = (0..10)
range
    .shuffled()
    .forEach { println(it) }

6.2. setOfNotNull()

The setOfNotNull() function makes a set consisting only of non-null values:

val someSet = setOfNotNull(null, 1, null, 2)
someSet
    .forEach { println(it) }

In the above example, only 1 and 2 will be printed.

6.3. minOf() and maxOf()

The minOf() and maxOf() will return the minimum and maximum value of the given selector function on collection items and throw NoSuchElementException if the collection is empty:

val someList = listOf(
    Some(1, "Z"),
    Some(2, "A"),
)

val minByName = someList.minOf { it.name }
val maxById = someList.maxOf { it.id }

6.3. sumOf()

The sumOf() function will return the sum of all values produced by the selector function applied to each element in the collection:

val anotherList = listOf(
    Some(1, "Z"),
    Some(2, "A"),
)

val sumOfIds = anotherList.sumOf { it.id }

Kotlin 1.4 introduced many more additional functions. If you would like to see the whole list, please see this reference page.

7. ArrayDeque Class Has Been Added

Some of you may have heard about the ArrayDeque, also known as an Array Double Ended Queue. In simple terms, it’s a growable array, which allows us to add and remove elements on both sides. Let’s see the example implementation:

val arrDeque = ArrayDeque(listOf(1,2))

arrDeque.addFirst(0) // [0,1,2]
arrDeque.addLast(3) // [0,1,2,3]

arrDeque.first() //0
arrDeque.last() //3

arrDeque.removeFirst() // [1,2,3]
arrDeque.removeLast() // [1,2]  

8. Additional Functions for String Manipulation

Kotlin 1.4 introduces also more improvements for String manipulations.

8.1. New Functions for StringBuilder

Some new functions, like deleteRange(), insertRange(), appendRange() and others has been added:

val one = StringBuilder("Hello World")

one.deleteRange(0,6) // "World"
one.insertRange(0, "Hello ", 0, 6) // "Hello World"
one.appendRange(" from Kotlin", 0,12) // "Hello World from Kotlin"

8.2. Existing Functions of StringBuilder Available in Common Library

Some of the existing functions of StringBuilder, like substring(), append(), or insert() will be available in the common library.

9. Bit Operations

Additionaly, new functions for bit operations has been added:

    • rotateLeft() and rotateRight() (experimental)
    • takeLowestOneBit()
    • takeHighestOneBit()
    • countTrailingZeroBits()
    • countLeadingZeroBits()

10. Mixing Positional and Named Arguments

So far, if we wanted to call any function using named arguments, we had to place them after all positional arguments (without names). Kotlin 1.4 introduces the possibility of mixing both types of arguments – as long as they remain in the correct order. Let’s look into the following examples:

someFun(1, "String", three = 1.0) // OK before Kotlin 1.4
someFun(1, two = "String", three = 1.0) // OK before Kotlin 1.4
someFun(one = 1, "String", three = 1.0) // compilation-error before Kotlin 1.4

As we can see, the third example won’t throw the compilation error starting from Kotlin 1.4 version.

5. Conclusion

I believe that this article on Kotlin 1.4 features gave you a little insight into this topic. To see the whole list of features and changes, please check out the official reference.

Do you like the way Kotlin language is evolving? What do you think about these new features? I would be really happy to hear your point of view (you can do that in the comment section, or for example by the contact form).

Share on facebook
Share on twitter
Share on linkedin

Leave a Comment

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

Subscribe to our Newsletter

Join the community and get free eBooks.

Image shows the covers of free ebooks accessible for newsletter subscribers.

You may opt out any time. Terms of Use and Privacy Policy

Find us also on...

Join the FREE weekly newsletter and get two free eBooks as well:

Image shows the covers of free ebooks accessible for newsletter subscribers.

You may opt out any time. Terms of Use and Privacy Policy

To make Codersee work, we log user data. By using our site, you agree to our Privacy Policy and Terms of Use.