Simple Kotlin Tips for Beginners

When beginning to learn a new programming language, it’s important to have an overview of the fundamentals. That said, here are some useful tricks that will help ease you into learning Kotlin if you’re just starting out.

Apply

A common use case for apply is to make additional configurations on a recently created object:

1
2
3
4
val turtle = Turtle().apply{
    Name = "Joe"
    Age = 50
}

Notice how when you use apply, it will return the object you modified back to you.

With

A common use case for with is to call multiple methods on the same object. In that case, this:

1
2
3
4
file.load()
file.modify()
file.modifyMore()
file.save()

will become this:

1
2
3
4
5
6
with(file){
    load()
    modify()
    modifyMore()
    save()
}

Keep in mind that the above returns the result of the last expression.

Method Returns Using =

If you have a method that contains only a single return statement, you can omit the return type, return keyword, and braces, and replace them all with =. In that case, this:

1
2
3
fun sum(val a: Int, val b: Int): Int {
    return a+b
}

becomes this:

1
fun sum(val a: Int, val b: Int) = a + b

Ranges

Ranges are useful for cycle conditions, as shown here:

1
for (i in 1..5) print(i) // results in "12345"

However, this doesn’t work in reverse:

1
for (i in 5..1) print(i) // prints nothing

Instead, here is the proper backward iteration:

1
for (i in 5 downTo 1) print(i) // results in "54321"

You can also use until, like so:

1
2
3
for (i in 0 until 5) { // results in "01234"
     println(i)
}

This is frequently used to iterate through collections:

1
2
3
for(i in 0 until list.size()){
    println(i)
}

When

When is a more powerful version of Java’s switch, and it combines nicely with ranges, as shown here:

Copy
1
2
3
4
5
when (x) {
    in 0 until 5 -> println("x is in range")
    is 10 -> println("the special case, when x is 10")
    else -> println("none of the above")
}

It can be also used as a return statement, but you need to either specify all possible cases (make it exhaustive) or include else:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enum class Theme {
    DEFAULT,
    DARK,
    XMAS
}

fun getThemeLogo() = when (theme) {
    DEFAULT -> getDefaultLogo()
    DARK -> getDarkLogo()
    XMAS -> getXmasLogo()
}

fun getThemeLogoExcludingPromos() = when (theme) {
    DEFAULT -> getDefaultLogo()
    DARK -> getDarkLogo()
    else -> getDefaultLogo()
}

Additionally, you can use when as an expression, but it doesn’t need to be exhaustive in this case:

1
2
3
4
5
6
fun showAnimations() {
    when (theme) {
        DEFAULT -> showAnimation()
        XMAS -> showXmasAnimation()
    }
}

Finally, when can be used along with smart casts:

1
2
3
4
when(file) {
    is Directory -> processDirectory()
    is Document -> processDocument()
}

Data Classes

Data classes are classes that have the specific purpose of holding data:

1
data class Turtle(val name: String, val age: Int)

The data class will have the following function out of the box:

toString of the form "Turtle(name=Joe, age=50)" equals() and hashCode() copy()

It will also become a subject for destructuring declarations:

1
2
3
4
val turtleJoe = Turtle("Joe", 50)
val (name, age) = turtleJoe
println(name)
println(age)

Static Fields and Constants

Static fields are commonly used in Java, but they are a bit tricky in Kotlin. The closest thing to the concept of static fields in Kotlin is a companion object declared inside the class.

Here is how you can declare a static constant:

1
2
3
class Theme {
    companion object { const val THEME_KEY = "a_theme_key" }
}

Null Safety

Kotlin provides tools to help you prevent the most common type of runtime exceptions: NullPointerExceptions (NPEs).

To do this, you first need to explicitly specify that you want some field/variable to hold null:

Copy
1
2
3
4
5
var text: String // can't hold null
text = null // compilation error

var textOrNull: String? // can hold null (specified by adding ?)
textOrNull = null // compiles just fine

If you use the second version, Kotlin will expect a null handling logic, and there are tools to simplify that as well.

Safe calls ?. to perform an action on a nullable object:

1
2
var textOrNull: String?
textOrNull?.length // will return length or null

The Elvis operator ?: specifies actions to take in case of a null:

1
textOrNull?.length ?: 0 // will return length or 0 in case of a null

There is also the let operator, which can be used if you need a code block to execute only when something isn’t null:

1
2
3
4
currentTheme?.let {
    applyTheme(theme)// we are certain it is not null here
    sendAnalyticsThemeEvent(theme)
}

Finally, there is !!, which converts any value to a non-null type and throws an exception if the value is null. This operator may look like an easy escape for null handling chores, but it should be avoided at all costs since Kotlin does so much to help to get rid of NPEs.

There is much more to Kotlin, but for the sake of simplicity, this is a good starting point. Hopefully, it will be a useful guide about frequently used Kotlin practices to help get you up and running.