Conditions and cycles

If expression

In Kotlin, if is an expression: it returns a value. Therefore, there is no need for ternary operators

val max = if (a > b) a else b
Copy the code

If branches can be blocks of code, in which case the final expression is the value of that block

val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}
Copy the code

When the expression

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")}}Copy the code

When can be used as either an expression or a statement. If it is treated as an expression, the value of the first eligible branch is the value of the entire expression; if used as a statement, individual branch values are ignored

If when is used as an expression, there must be an else branch, unless the compiler can detect that all possible cases have been overridden (such as enumeration classes)

You can use any expression, not just a constant, as a branching condition

when (x) {
    s.toInt() -> print("s encodes x")
    else -> print("s does not encode x")}Copy the code

You can also detect a value in (in) or not in (! In) an interval or set:

when (x) {
    in 1.10. -> print("x is in the range")
    in validNumbers -> print("x is valid")!in 10.20. -> print("x is outside the range")
    else -> print("none of the above")}Copy the code

📢 when can also be used to replace if-else if chains. If no arguments are provided, all branch conditions are simple Boolean expressions, and a branch is executed when its condition is true:

when {
    x.isOdd() -> print("x is odd")
    y.isEven() -> print("y is even")
    else -> print("x+y is odd")}Copy the code

Capture the subject of when into a variable using the following syntax

fun Request.getBody(a) =
        when (val response = executeRequest()) {
            is Success -> response.body
            is HttpError -> throw HttpException(response.status)
        }
Copy the code

Variables introduced into the when subject are limited to the scope of the WHEN subject

The For loop

The for loop can iterate over any object that provides an iterator

for (item in collection) print(item)
Copy the code

To iterate over numeric intervals, use interval expressions

fun main(a) {
    for (i in 1.3.) {
        println(i)
    }
    for (i in 6 downTo 0 step 2) {
        println(i)
    }
}
Copy the code

A for loop for an interval or array is compiled as an index-based loop that does not create iterators

Traversing an index of a group of numbers can be done this way

fun main(a) {
val array = arrayOf("a"."b"."c")
    for (i in array.indices) {
        println(array[i])
    }
}
Copy the code

Or you can use the withIndex library function:

fun main(a) {
    val array = arrayOf("a"."b"."c")
    for ((index, value) in array.withIndex()) {
        println("the element at $index is $value")}}Copy the code

Return and jump

Three structured jumps: Return, break, and continue

Each of these expressions can be used as part of a larger expression:

val s = person.name ?: return
Copy the code

Break and Continue labels

Any expression in Kotlin can be marked with a tag. The format of the tag is an identifier followed by the @ symbol

  • Jumps and ends the loop specified by the label
loop@ for (i in 1.100.) {
    for (j in 1.100.) {
        if(...)break@loop}}Copy the code
  • Returns from a lambda expression

Without the label, as in 🌰, return directly to the caller of foo()

fun foo(a) {
    listOf(1.2.3.4.5).forEach {
        if (it == 3) return // non-local returns directly to the caller of foo()
        print(it)
    }
    println("this point is unreachable")}Copy the code

If you want to return from a lambda expression, you can label it and qualify the return

fun foo(a) {
    listOf(1.2.3.4.5).forEach lit@{
        if (it == 3) return@lit // Local returns to the caller of the lambda expression -- the forEach loop
        print(it)
    }
    print(" done with explicit label")}Copy the code

It is usually more convenient to use an implicit label because the label has the same name as the function that accepts the lambda

fun foo(a) {
    listOf(1.2.3.4.5).forEach {
        if (it == 3) return@forEach // Local returns to the caller of the lambda expression -- the forEach loop
        print(it)
    }
    print(" done with implicit label")}Copy the code

Alternatively, we can replace lambda expressions with an anonymous function. A return statement inside an anonymous function is returned from the anonymous function itself

fun foo(a) {
    listOf(1.2.3.4.5).forEach(fun(value: Int) {
        if (value == 3) return  // local returns to the caller of the anonymous function -- forEach loop
        print(value)
    })
    print(" done with anonymous function")}Copy the code

The previous three examples are similar to the use of continue in a regular loop and do not have a direct equivalent of break, but can be simulated by adding another layer of nested lambda expressions and returning non-locally from them

fun foo(a) {
    / /?? â‘  Run
    run loop@{
        listOf(1.2.3.4.5).forEach {
            if (it == 3) return@loop // Returns nonlocally from the lambda expression passed to run
            print(it)
        }
    }
    print(" done with nested loop")}Copy the code

(?????? When it comes to returning a value, the parser preferentially uses tag-qualified returns:

return@a 1
Copy the code

This means “return 1 to @ A”, not “return a labeled expression (@a 1)”.

abnormal

Try is an expression

Try is an expression, which means it can have a return value:

val a: Int? = try { input.toInt() } catch (e: NumberFormatException) { null }
Copy the code

The return value of a try- expression is either the last expression in a try block or (all) the last expression in a catch block. The contents of the finally block do not affect the result of the expression

B. abnormal

Kotlin has not been tested for any anomalies, which can be seen in Effective Java, 3rd edition, Article 77:

A few small program tests suggest that exception specifications improve both developer productivity and code quality, but experience with large software projects suggests a different conclusion — reduced productivity and little or no improvement in code quality.

Nothing type

In Kotlin, a throw is an expression, which is of type Nothing. This type has no value and is used to mark code locations that can never be reached.

val s = person.name ?: throw IllegalArgumentException("Name required")
Copy the code

You can use Nothing to mark a function that never returns

val s = person.name ?: fail("Name required")
println(s)     // it is known here that "s" is initialized
Copy the code

When you call this function, the compiler knows that execution will stop after the call

question list

  • ?? Run, run, run
  • ?? â‘¡ Where is the return value used

other

If you are new to Kotlin and want to review the knowledge quickly, you can check it out here.

Official Chinese document:

  • www.kotlincn.net/docs/refere…
  • book.kotlincn.net/

Run Kotlin online:

  • www.bejson.com/runcode/kot…
  • play.kotlinlang.org/