Spec-Zone.ru › Kotlin 2

Условия и циклы

Kotlin предоставляет гибкие инструменты для управления потоком выполнения программы. Используйте if, when и циклы, чтобы задавать понятную и выразительную логику для условий.

Выражение if

Чтобы использовать if в Kotlin, добавьте проверяемое условие в круглые скобки (), а действие, которое нужно выполнить, если результат равен true, — в фигурные скобки {}. Для дополнительных ветвей и проверок можно использовать else и else if.

Также можно записать if как выражение, что позволяет присвоить возвращаемое им значение непосредственно переменной. В этой форме требуется ветвь else. Выражение if выполняет ту же функцию, что и тернарный оператор (condition ? then : else) в других языках.

Например:

fun main() {
    val heightAlice = 160
    val heightBob = 175

    //sampleStart
    var taller = heightAlice
    if (heightAlice < heightBob) taller = heightBob

    // Uses an else branch
    if (heightAlice > heightBob) {
        taller = heightAlice
    } else {
        taller = heightBob
    }

    // Uses if as an expression
    taller = if (heightAlice > heightBob) heightAlice else heightBob

    // Uses else if as an expression:
    val heightLimit = 150
    val heightOrLimit = if (heightLimit > heightAlice) heightLimit else if (heightAlice > heightBob) heightAlice else heightBob

    println("Taller height is $taller")
    // Taller height is 175
    println("Height or limit is $heightOrLimit")
    // Height or limit is 175
    //sampleEnd
}

Каждая ветвь выражения if может быть блоком, значением которого становится результат последнего выражения:

fun main() {
    //sampleStart
    val heightAlice = 160
    val heightBob = 175

    val taller = if (heightAlice > heightBob) {
        print("Choose Alice\n")
        heightAlice
    } else {
        print("Choose Bob\n")
        heightBob
    }

    println("Taller height is $taller")
    //sampleEnd
}

Выражения и инструкции when

when — это условное выражение, которое выполняет код в зависимости от нескольких возможных значений или условий. Оно похоже на инструкцию switch в Java, C и других языках. when вычисляет свой аргумент и сравнивает результат с каждой ветвью по порядку, пока не будет выполнено условие одной из ветвей. Например:

fun main() {
    //sampleStart
    val userRole = "Editor"
    when (userRole) {
        "Viewer" -> print("User has read-only access")
        "Editor" -> print("User can edit content")
        else -> print("User role is not recognized")
    }
    // User can edit content
    //sampleEnd
}

when можно использовать как выражение или как инструкцию. Как выражение, when возвращает значение, которое можно использовать далее в коде. Как инструкция, when выполняет действие, не возвращая результат:

Выражение

Инструкция

// Returns a string assigned to the 
// text variable
val text = when (x) {
    1 -> "x == 1"
    2 -> "x == 2"
    else -> "x is neither 1 nor 2"
}
// Returns no result but triggers a 
// print statement
when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> print("x is neither 1 nor 2")
}

Во-вторых, when можно использовать как с проверяемым значением, так и без него. В обоих случаях поведение остается одинаковым. Использование проверяемого значения обычно делает код более понятным и удобным в сопровождении, поскольку ясно показывает, что именно проверяется.

С проверяемым значением x

Без проверяемого значения

when(x) { ... }
when { ... }

От того, как вы используете when, зависит необходимость охватить все возможные случаи в ветвях. Охват всех возможных случаев называется полнотой.

Инструкции

Если вы используете when как инструкцию, охватывать все возможные случаи не нужно. В этом примере некоторые случаи не охвачены, поэтому ни одна ветвь не выполняется. При этом ошибки не возникает:

fun main() {
    //sampleStart
    val deliveryStatus = "OutForDelivery"
    when (deliveryStatus) {
        // Not all cases are covered
        "Pending" -> print("Your order is being prepared")
        "Shipped" -> print("Your order is on the way")
    }
    //sampleEnd
}

Как и в случае с if, каждая ветвь может быть блоком, а ее значение определяется последним выражением в блоке.

Выражения

Если вы используете when как выражение, вы должны охватить все возможные случаи. Значением всего выражения становится значение первой совпавшей ветви. Если охвачены не все случаи, компилятор выдает ошибку.

Если у выражения when есть проверяемое значение, можно использовать ветвь else, чтобы убедиться, что охвачены все возможные случаи, но это не обязательно. Например, если проверяемое значение имеет тип Boolean, классом enum, классом sealed или одним из их nullable-вариантов, все случаи можно охватить без ветви else:

import kotlin.random.Random
//sampleStart
enum class Bit {
    ZERO, ONE
}

fun getRandomBit(): Bit {
    return if (Random.nextBoolean()) Bit.ONE else Bit.ZERO
}

fun main() {
    val numericValue = when (getRandomBit()) {
        // No else branch is needed because all cases are covered
        Bit.ZERO -> 0
        Bit.ONE -> 1
    }

    println("Random bit as number: $numericValue")
    // Random bit as number: 0
    //sampleEnd
}

Чтобы упростить выражения when и сократить повторения, попробуйте контекстно-зависимое разрешение (сейчас эта возможность доступна в предварительной версии). Эта возможность позволяет опускать имя типа при использовании элементов enum или членов sealed-класса в выражениях when, если ожидаемый тип известен.

Подробнее см. в разделе Предварительная версия контекстно-зависимого разрешения или в соответствующем предложении KEEP.

Если у выражения when нет проверяемого значения, у него должна быть ветвь else, иначе компилятор выдаст ошибку. Ветвь else выполняется, если ни одно из остальных условий ветвей не выполнено:

fun main() {
    //sampleStart
    val localFileSize = 1200
    val remoteFileSize = 1200

    val message = when {
        localFileSize > remoteFileSize -> "Local file is larger than remote file"
        localFileSize < remoteFileSize -> "Local file is smaller than remote file"
        else -> "Local and remote files are the same size"
    }

    println(message)
    // Local and remote files are the same size
    //sampleEnd
}

Другие способы использования when

Выражения и инструкции when позволяют упростить код, обработать несколько условий и выполнить проверки типов разными способами.

Объедините несколько условий в одной ветви с помощью запятых:

fun main() {
    val ticketPriority = "High"
    //sampleStart
    when (ticketPriority) {
        "Low", "Medium" -> print("Standard response time")
        else -> print("High-priority handling")
    }
    //sampleEnd
}

Используйте в качестве условий ветвей выражения, результатом которых является true или false:

fun main() {
    val storedPin = "1234"
    val enteredPin = 1234
  
    //sampleStart
    when (enteredPin) {
        // Expression
        storedPin.toInt() -> print("PIN is correct")
        else -> print("Incorrect PIN")
    }
    //sampleEnd
}

Проверьте, входит ли значение в диапазон или коллекцию, с помощью ключевых слов in или !in:

fun main() {
    val x = 7
    val validNumbers = setOf(15, 16, 17)

    //sampleStart
    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")
    }
    //sampleEnd
}

Проверьте тип значения с помощью ключевых слов is или !is. Благодаря умным приведениям типов можно обращаться непосредственно к функциям-членам и свойствам этого типа:

fun hasPrefix(input: Any): Boolean = when (input) {
    is String -> input.startsWith("ID-")
    else -> false
}

fun main() {
    val testInput = "ID-98345"
    println(hasPrefix(testInput))
    // true
}

Используйте when вместо традиционной цепочки if-else-if. Без проверяемого значения условия ветвей — это просто логические выражения. Выполняется первая ветвь с условием true:

fun Int.isOdd() = this % 2 != 0
fun Int.isEven() = this % 2 == 0

fun main() {
    //sampleStart
    val x = 5
    val y = 8

    when {
        x.isOdd() -> print("x is odd")
        y.isEven() -> print("y is even")
        else -> print("x+y is odd")
    }
    // x is odd
    //sampleEnd
}

Наконец, сохраните проверяемое значение в переменной, используя следующий синтаксис:

fun main() {
    val message = when (val input = "yes") {
        "yes" -> "You said yes"
        "no" -> "You said no"
        else -> "Unrecognized input: $input"
    }

    println(message)
    // You said yes
}

Область видимости переменной, объявленной как проверяемое значение, ограничена телом выражения или инструкции when.

Условия-ограничители

Условия-ограничители позволяют добавить несколько условий к ветвям выражения или инструкции when, делая сложный поток выполнения более понятным и лаконичным. Условия-ограничители можно использовать с when, если у него есть проверяемое значение.

Разместите условие-ограничитель после основного условия в той же ветви, отделив его с помощью if:

sealed interface Animal {
    data class Cat(val mouseHunter: Boolean) : Animal
    data class Dog(val breed: String) : Animal
}

fun feedDog() = println("Feeding a dog")
fun feedCat() = println("Feeding a cat")

//sampleStart
fun feedAnimal(animal: Animal) {
    when (animal) {
        // Branch with only primary condition
        // Calls feedDog() when animal is Dog
        is Animal.Dog -> feedDog()
        // Branch with both primary and guard conditions
        // Calls feedCat() when animal is Cat and not mouseHunter
        is Animal.Cat if !animal.mouseHunter -> feedCat()
        // Prints "Unknown animal" if none of the above conditions match
        else -> println("Unknown animal")
    }
}

fun main() {
    val animals = listOf(
        Animal.Dog("Beagle"),
        Animal.Cat(mouseHunter = false),
        Animal.Cat(mouseHunter = true)
    )

    animals.forEach { feedAnimal(it) }
    // Feeding a dog
    // Feeding a cat
    // Unknown animal
}
//sampleEnd

Нельзя использовать условия-ограничители, если несколько условий разделены запятой. Например:

0, 1 -> print("x == 0 or x == 1")

В одном выражении или инструкции when можно сочетать ветви с условиями-ограничителями и без них. Код в ветви с условием-ограничителем выполняется, только если и основное условие, и условие-ограничитель принимают значение true. Если основное условие не совпадает, условие-ограничитель не проверяется.

Поскольку инструкции when не требуют охватывать все случаи, использование условий-ограничителей в инструкциях when без ветви else означает, что при отсутствии совпадений код не выполняется.

В отличие от инструкций, выражения when должны охватывать все случаи. Если в выражениях when используются условия-ограничители без ветви else, компилятор требует обработать каждый возможный случай, чтобы избежать ошибок во время выполнения.

Объедините несколько условий-ограничителей в одной ветви с помощью логических операторов && (И) или || (ИЛИ). Чтобы избежать неоднозначности, заключайте логические выражения в круглые скобки:

when (animal) {
    is Animal.Cat if (!animal.mouseHunter && animal.hungry) -> feedCat()
}

Условия-ограничители также поддерживают else if:

when (animal) {
    // Checks if `animal` is `Dog`
    is Animal.Dog -> feedDog()
    // Guard condition that checks if `animal` is `Cat` and not `mouseHunter`
    is Animal.Cat if !animal.mouseHunter -> feedCat()
    // Calls giveLettuce() if none of the above conditions match and animal.eatsPlants is true
    else if animal.eatsPlants -> giveLettuce()
    // Prints "Unknown animal" if none of the above conditions match
    else -> println("Unknown animal")
}

Генерация байт-кода для JVM

При компиляции кода Kotlin для JVM 21 или новее компилятор генерирует инструкцию invokedynamic для подходящих выражений when. В результате получается байт-код меньшего размера, похожий на байт-код, создаваемый инструкциями switch в Java.

Компилятор использует invokedynamic с методом SwitchBootstraps.typeSwitch(), если выполняются все следующие условия:

  • Все условия, кроме else, представляют собой проверки is или null.

  • Выражение when не содержит условий-ограничителей (if).

  • Условия не включают типы, которые нельзя проверить непосредственно, например изменяемые коллекции Kotlin (MutableList) или функциональные типы (kotlin.Function1, kotlin.Function2 и т. д.).

  • Выражение when содержит как минимум два условия, помимо else.

  • Во всех ветвях проверяется одно и то же проверяемое значение выражения when.

Например:

open class Shape

class Circle : Shape()
class Rectangle : Shape()
class Triangle : Shape()

fun countCorners(shape: Shape) = when (shape) {
    is Circle -> 0
    is Rectangle -> 4
    is Triangle -> 3
    else -> -1
}

Приведенное здесь выражение when (shape) компилируется в одно переключение по типу invokedynamic вместо нескольких проверок instanceof в байт-коде.

Циклы for

Используйте цикл for для перебора коллекции, массива или диапазона:

for (item in collection) print(item)

Телом цикла for может быть блок в фигурных скобках {}.

fun main() {
    val shoppingList = listOf("Milk", "Bananas", "Bread")
    //sampleStart
    println("Things to buy:")
    for (item in shoppingList) {
        println("- $item")
    }
    // Things to buy:
    // - Milk
    // - Bananas
    // - Bread
    //sampleEnd
}

Диапазоны

Чтобы перебрать диапазон чисел, используйте выражение диапазона с операторами .. и ..<:

fun main() {
//sampleStart
    println("Closed-ended range:")
    for (i in 1..6) {
        print(i)
    }
    // Closed-ended range:
    // 123456
  
    println("\nOpen-ended range:")
    for (i in 1..<6) {
        print(i)
    }
    // Open-ended range:
    // 12345
  
    println("\nReverse order in steps of 2:")
    for (i in 6 downTo 0 step 2) {
        print(i)
    }
    // Reverse order in steps of 2:
    // 6420
//sampleEnd
}

Массивы

Чтобы перебрать массив или список с индексом, можно использовать свойство indices:

fun main() {
    val routineSteps = arrayOf("Wake up", "Brush teeth", "Make coffee")
    //sampleStart
    for (i in routineSteps.indices) {
        println(routineSteps[i])
    }
    // Wake up
    // Brush teeth
    // Make coffee
    //sampleEnd
}

В качестве альтернативы можно использовать функцию .withIndex() из стандартной библиотеки:

fun main() {
    val routineSteps = arrayOf("Wake up", "Brush teeth", "Make coffee")
    //sampleStart
    for ((index, value) in routineSteps.withIndex()) {
        println("The step at $index is \"$value\"")
    }
    // The step at 0 is "Wake up"
    // The step at 1 is "Brush teeth"
    // The step at 2 is "Make coffee"
    //sampleEnd
}

Итераторы

Цикл for выполняет итерацию по любому объекту, предоставляющему итератор. Коллекции предоставляют итераторы по умолчанию, тогда как диапазоны и массивы компилируются в циклы с индексацией.

Вы можете создать собственный итератор, предоставив функцию-член или функцию-расширение с именем iterator(), которая возвращает Iterator<>. Функция iterator() должна иметь функцию next() и функцию hasNext(), возвращающую Boolean.

Проще всего создать собственный итератор для класса, унаследовав его от интерфейса Iterable<T> и переопределив уже имеющиеся функции iterator(), next() и hasNext(). Например:

class Booklet(val totalPages: Int) : Iterable<Int> {
    override fun iterator(): Iterator<Int> {
        return object : Iterator<Int> {
            var current = 1
            override fun hasNext() = current <= totalPages
            override fun next() = current++
        }
    }
}

fun main() {
    val booklet = Booklet(3)
    for (page in booklet) {
        println("Reading page $page")
    }
    // Reading page 1
    // Reading page 2
    // Reading page 3
}

Подробнее об интерфейсах и наследовании.

В качестве альтернативы можно создать функции с нуля. В этом случае добавьте к функциям ключевое слово operator:

//sampleStart
class Booklet(val totalPages: Int) {
    operator fun iterator(): Iterator<Int> {
        return object {
            var current = 1

            operator fun hasNext() = current <= totalPages
            operator fun next() = current++
        }.let {
            object : Iterator<Int> {
                override fun hasNext() = it.hasNext()
                override fun next() = it.next()
            }
        }
    }
}
//sampleEnd

fun main() {
    val booklet = Booklet(3)
    for (page in booklet) {
        println("Reading page $page")
    }
    // Reading page 1
    // Reading page 2
    // Reading page 3
}

Циклы while

Циклы while и do-while непрерывно выполняют код в теле, пока условие истинно. Они различаются моментом проверки условия:

  • while проверяет условие и, если оно истинно, выполняет код в теле, а затем возвращается к проверке условия.

  • do-while выполняет код в теле, а затем проверяет условие. Если оно истинно, цикл повторяется. Поэтому тело do-while выполняется как минимум один раз независимо от условия.

В цикле while поместите проверяемое условие в круглые скобки (), а тело — в фигурные скобки {}:

fun main() {
    var carsInGarage = 0
    val maxCapacity = 3
//sampleStart
    while (carsInGarage < maxCapacity) {
        println("Car entered. Cars now in garage: ${++carsInGarage}")
    }
    // Car entered. Cars now in garage: 1
    // Car entered. Cars now in garage: 2
    // Car entered. Cars now in garage: 3

    println("Garage is full!")
    // Garage is full!
//sampleEnd
}

В цикле do-while сначала поместите тело в фигурные скобки {}, а затем проверяемое условие в круглые скобки ():

import kotlin.random.Random

fun main() {
    var roll: Int
//sampleStart
    do {
        roll = Random.nextInt(1, 7)
        println("Rolled a $roll")
    } while (roll != 6)
    // Rolled a 2
    // Rolled a 6
    
    println("Got a 6! Game over.")
    // Got a 6! Game over.
//sampleEnd
}

Break и continue в циклах

В Kotlin в циклах поддерживаются традиционные операторы break и continue. См. раздел Возвраты и переходы.

21 августа 2026 г.
Псевдонимы типовВозвраты и переходы

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/control-flow.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API