Kotlin Control Statements

Conditional Statements

if Statement

if(expr) stmt1 else stmt2 executes stmt1 if expr is true, and stmt2 otherwise.

if (a > b) {
    println("Big")
} else {
    println("Small")
}

Let’s make the main function change the string according to the received argument if args is not empty. The syntax for branching processing by condition is if-else, which is familiar from Java.

Example: Check whether args is not empty

fun main(args: Array<String>) {
  if (args.isNotEmpty()) {
    println("Hello, ${args[0]}!")
  } else {
    println("Hello, world!")
  }
}

The isNotEmpty method checks whether the array is not empty. If the array is not empty, isNotEmpty returns true and executes the block following if. Otherwise, it executes the block following else. Like Java’s if-else, braces ({ }) can be omitted only when there is one statement in the block after branching.

In Kotlin, if-else is an expression. if-else returns a value.

var c = if (a > b) a else b

This behaves like Java’s ternary operator. Rewriting the example above gives the following.

Example: if-else is an expression.

fun main(args: Array<String>) {
  val name = if (args.isNotEmpty()) args[0] else "名無しさん"
  println("Hello, ${name}!")
}

Kotlin has no ternary expression operator, so it must be expressed with an if statement as above.

In Java, the ternary operator is written as (condition) ? a : b, but Kotlin does not support the ternary operator.

Loop Control

for Loop

The basic form of a for loop is for (... in ...) ..., and it is used to iterate over ranges, arrays, or collections.

for (i in 1..10) {
    println(i)
}

for (i in 10 downTo 0 step 2) {
    println(i)
}

var colors = arrayOf("Red", "Green", "Blue")
for (color in colors) {
    println(color)
}

If you want the main function to print Hello for multiple command-line arguments, use a for loop.

Example: Repeat Hello for each element of args.

fun main(args: Array<String>) {
  for (name in args) {
    println("Hello, ${name}!")
  }
}

Kotlin’s for is similar to Java’s enhanced for statement. Kotlin for does not support the style of loop that increments a loop counter manually.

forEach Loop

forEach and forEachIndexed repeat processing for arrays or collections.

var a = arrayOf("Red", "Green", "Blue")

a.forEach {
    value -> println(value)
}

a.forEachIndexed {
    index, value -> println("${index}: ${value}")
}

The following example is a program that iterates over and prints a list in several ways.

ForTutorial.kt

fun main() {
    val langList = listOf("javascript", "python", "kotlin", "java", "go")

    println("========= for loop =============");
    for (item in langList) {
        println(item)
    }

    println("========= for loop index =============");
    for (index in langList.indices) {
        println("${index} = ${langList[index]}")
    }

    println("========= for each loop =============");
    langList.forEachIndexed { index, value ->
        println("$index = $value")
    }
}

Output:

========= for loop =============
javascript
python
kotlin
java
go
========= for loop index =============
0 = javascript
1 = python
2 = kotlin
3 = java
4 = go
========= for each loop =============
0 = javascript
1 = python
2 = kotlin
3 = java
4 = go

A for statement can iterate over values. Writing for (item in list) retrieves each value from list and receives it in the item variable.

Writing for (index in list.indices) receives the index value of the item in the index variable. Since it receives the index, you can also access list[index] and retrieve the corresponding value.

Using the forEachIndexed() method lets you receive both index and value. In Java, you would need to create a separate variable and add an increment operator, but in Kotlin this method solves it.

while Loop

while repeats work while the condition is satisfied.

var i = 10
while (i > 0) {
    println(i--)
}

Code using while is as follows.

WhileTutorial.kt

fun main(args:Array<String>) {
    val mostLang = listOf("javascript", "python", "kotlin", "java", "go")

    println("== while case 1 ==============")
    var i = 0
    while (true) {
        if (i == mostLang.size) {
            break
        }
        println(mostLang[i])
        i++
    }

    println("== while case 2 ==============")
    var j = 0
    while (j < mostLang.size) {
        println(mostLang[j])
        j++
    }
}
== while case 1 ==============
javascript
python
kotlin
java
go
== while case 2 ==============
javascript
python
kotlin
java
go

do-while Loop

do ... while repeats the loop until the condition is no longer satisfied.

var i = 10
do {
    println(i--)
} while (i > 0)

Branching Statements

break Statement

break exits the innermost loop.

for (i in 1..5) {
    if (i == 2) {
        break
    }
    println(i)
}

continue Statement

continue starts the next iteration of the innermost loop.

for (i in 1..5) {
    if (i == 2) {
        continue
    }
    println(i)
}

when Expression

when returns different values depending on conditions. With an is statement, processing can be distributed by data type.

fun describe(obj: Any): String =
    when (obj) {
        1          -> "One"
        in 2..3    -> "Two or Three"
        "Hello"    -> "Greeting"
        is Long    -> "Long"
        !is String -> "Not a string"
        else       -> "Unknown"
    }

It looks similar to a switch case statement, but it is slightly different. In a normal switch statement, each case usually contains one type, but in when, all types can be used. There is also no need to add a break statement after the logic is complete. When the matching condition is found, it exits immediately. else is used instead of default.

WhenTutorial.kt

fun whenFunc(value: Any) {
    when (value) {
        0 -> println("0 입니다.")
        "two" -> println("two 입니다.")
        3.14 -> println("3.4 입니다.")
        else -> println("아무것도 해당되지 않아요")
    }
}

fun main(args: Array<String>) {
    whenFunc(0)
    whenFunc("two")
    whenFunc(3.14)
    whenFunc(1234)
}
0 입니다.
two 입니다.
3.4 입니다.
아무것도 해당되지 않아요

Others

Label (@)

By specifying a label with @, you can specify the target loop for break and continue.

foo@ for (i in 1..5) {
    for (j in 1..5) {
        if (i == 3 && j == 3) break@foo
        println("$i $j")
    }
}

If you use return in a function’s lambda expression, it normally returns from the function, but you can specify an @ label and return from the lambda expression.

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach baa@ {
        if (it == 3) return@baa
        println(it)		// 1, 2, 4, 5
    }
}

Classes and functions implicitly have labels with their class name or function name. As shown below, an inner class can also refer to an instance of the outer class.

class A {
    val foo = "AAA"
    inner class B {
        val foo = "BBB"
        fun foo() = println("${this.foo} ${this@A.foo}")	// BBB AAA
    }
}

fun main() {
    A().B().foo()
}

Exception Handling (try, throw, catch, finally)

The following is an example of exception handling.

try {
    if (...) {
        throw IllegalStateException()
    } catch (e: Exception) {
        println(e)
    } finally {
        println("Finally")
    }
}

try starts exception handling. throw throws an exception. catch catches an exception. finally always executes the described processing regardless of whether an exception occurs.