Всем привет, меня зовут Сергей Прощаев. Я техлид в FinTech и преподаю на курсах в Otus. Мы продолжаем наше погружение в Kotlin.
В прошлый раз мы говорили о типах данных и переменных. Это был фундамент. Но данные без действий мертвы. Самое интересное начинается, когда программе нужно принимать решения: если клиент VIP, дать ему кэшбэк 5%, иначе — 1%. Или повторять действие: отправлять запрос на сервер, пока не получим ответ.
Знаете, в чём беда многих новичков? Они знают синтаксис if и for, но пишут такие «спагетти», что через месяц сами не могут разобраться. Сегодня мы не просто пройдем тему «Условные операторы и циклы». Мы разберем, как управлять ходом программы правильно, красиво и эффективно. Чтобы ваш код читался как хорошая книга, а не как шифровка.
Движемся дальше!
1. Булева вселенная: Boolean и сравнение
Всё начинается с истины или лжи. Тип Boolean (true/false) — это основа любого условия.
Вспомним прошлую статью:
val isEnabled = true val hasAccess = false
Но чаще мы получаем Boolean в результате сравнений. Тут всё привычно, но есть нюанс.
fun main() { val a = 10 val b = 20 println(a > b) // false println(a < b) // true println(a >= 10) // true println(a == 10) // true println(a != b) // true }
Важный момент для тех, кто пришел из Java или других языков. В Kotlin есть два вида равенства:
==— структурное равенство (проверяет содержимое). В Java для этого нужно писатьequals().===— ссылочное равенство (проверяет, указывают ли переменные на один и тот же объект в памяти).
Для базовых типов (числа, строки) это редко нужно, но когда дойдете до классов, запомните: в 99% случаев вы будете использовать ==. Компилятор Kotlin сам под капотом вызовет equals.
2. if — это не просто оператор. Это выражение
И вот тут начинается магия Kotlin, которая бесит Java‑разработчиков на код‑ревью (в хорошем смысле).
В Java if — это инструкция (statement). Она ничего не возвращает.
В Kotlin if — это выражение (expression). Оно возвращает значение!
Смотрите, как мы обычно писали в Java:
// Java-style int max; if (a > b) { max = a; } else { max = b; }
А теперь, как это делается в Kotlin:
fun main() { val a = 15 val b = 20 val max = if (a > b) a else b println("Максимум: $max") // Максимум: 20 }
Лаконично, правда? Это полностью заменило тернарный оператор ? :, который многие не любят из‑за сложности чтения.
Когда это спасает? Представьте, что мы считаем комиссию за перевод. Если сумма больше 1000, комиссия фиксированная, если меньше — процентная.
fun calculateFee(amount: Double): Double { return if (amount >= 1000.0) { println("Применяем фиксированную комиссию") 50.0 // Последнее выражение в блоке — это результат if } else { println("Применяем процентную комиссию") amount * 0.02 } }
Код стал декларативным. Мы говорим: «комиссия равна — если сумма больше 1000, то 50, иначе 2%». Читать такой код — одно удовольствие.
3. Визуализируем поток
Чтобы закрепить, как работает ветвление, давайте посмотрим на простую блок‑схему, представленную на рисунке 1. Допустим, у нас есть логин: если имя «Admin», пускаем, если нет — проверяем пароль.

Таких ромбов в коде могут быть десятки. И чем их больше, тем важнее писать их красиво. Для этого в Kotlin есть король.
4. when — швейцарский нож управляющих конструкций
Забудьте про switch-case. В Kotlin есть when, и он в сто раз мощнее.
Пример 1: Простая замена if-else if
Допустим, мы обрабатываем HTTP‑статусы.
fun handleHttpStatus(code: Int): String { return when (code) { 200 -> "OK" 404 -> "Not Found" 500 -> "Internal Server Error" else -> "Unknown Status" } }
Чисто, красиво, без break.
Пример 2: Проверка на вхождение в диапазон (об этом чуть позже)
fun getTemperatureCategory(celsius: Int): String { return when (celsius) { in -50..0 -> "Морозно" in 1..15 -> "Прохладно" in 16..30 -> "Тепло" in 31..50 -> "Жарко" else -> "Экстремально" } }
Пример 3: Проверка типа (пригодится, когда изучите наследование)
fun printType(obj: Any) { when (obj) { is String -> println("Это строка длиной ${obj.length}") is Int -> println("Это число: $obj") else -> println("Что-то другое") } }
Пример 4: when без аргумента (как замена цепочке if)
Иногда нужно проверить сложные условия.
fun getDiscount(customerType: String, years: Int, amount: Double): Double { return when { customerType == "vip" && years > 5 -> 0.20 customerType == "vip" -> 0.15 amount > 10000 -> 0.10 years > 3 -> 0.05 else -> 0.0 } }
Видите? Мы убрали лесенку из if-else. Код читается как таблица правил. Именно так мы и пишем логику в наших FinTech‑сервисах — это best practice.
5. Диапазоны (Ranges): синтаксический сахар, который вы полюбите
Мы уже использовали in 1..10. Давайте разберем, что это такое.
Диапазон (IntRange) — это просто объект, который представляет интервал от и до.
val oneToTen = 1..10 val tenToOne = 10 downTo 1 val evenNumbers = 0..100 step 2 val letters = 'A'..'Z' fun main() { println(5 in oneToTen) // true println(15 in oneToTen) // false println('C' in letters) // true }
Зачем это нужно? Кроме проверок в when, это незаменимо в циклах.
6. Циклы: повторение — мать учения
for по диапазонам и коллекциям
В Kotlin нет классического for (int i = 0; i < 10; i++). Вместо этого — итерация по диапазонам.
fun main() { // Вывести числа от 1 до 5 for (i in 1..5) { println("Индекс: $i") } // Вывести числа от 5 до 1 (обратный порядок) for (i in 5 downTo 1) { println("Обратный: $i") } // Перебор с шагом for (i in 0..10 step 2) { println("Четное: $i") } // Если нужно перебрать массив/список и получить индексы val fruits = listOf("Apple", "Banana", "Orange") for (index in fruits.indices) { println("$index -> ${fruits[index]}") } // Лучший способ — сразу получить и индекс и значение (реальная практика) for ((index, fruit) in fruits.withIndex()) { println("$index -> $fruit") } }
while и do‑while
Работают классически. Используем, когда количество итераций неизвестно.
fun main() { var x = 5 while (x > 0) { println("Осталось: $x") x-- } var input: String? do { print("Введите 'exit' для выхода: ") input = readlnOrNull() } while (input != "exit") }
repeat — простая вещь, которую многие не знают
Нужно просто повторить действие N раз? Забудьте про for i in 1..N.
import kotlin.repeat fun main() { repeat(3) { iterationNumber -> println("Повторение номер $iterationNumber") // iterationNumber идет от 0 } }
Идеально для тестовых заглушек или простых утилит.
7. Джампы: return, break, continue и их метки
Это та тема, где новички часто теряются, особенно когда есть вложенные циклы.
return— выходит из функции.break— прерывает текущий цикл.continue— переходит к следующей итерации цикла.
Проблема: как выйти из внешнего цикла, находясь во внутреннем?
В Java пришлось бы использовать флаг found = true;. В Kotlin для этого есть метки (labels).
fun main() { outer@ for (i in 1..3) { for (j in 1..3) { if (i == 2 && j == 2) { println("Нашли! Выходим из внешнего цикла на метке outer") break@outer // Выходим из цикла, помеченного outer } println("i=$i, j=$j") } } println("Готово") }
Вывод будет:
i=1, j=1 i=1, j=2 i=1, j=3 i=2, j=1 Нашли! Выходим из внешнего цикла на метке outer Готово
Без метки break просто прервал бы внутренний цикл, и внешний продолжился бы с i=3.
8. Реальная история: Как мы перестали писать простыни из if‑else и сэкономили 10% времени
Расскажу случай, который произошел у нас в команде, когда мы переписывали скоринговый модуль (оценка кредитоспособности клиента).
Исходный код на Java был написан 5 лет назад. Там был метод calculateRiskScore, который представлял собой монстра строк на 300. Это была бесконечная лестница if-else:
if (client.getAge() > 60 && client.hasPension()) { // ... 20 строк логики } else if (client.getAge() > 60) { // ... еще 15 строк } else if (client.getIncome() > 100000 && client.getJob().isStable()) { // ... ад } // и так далее
Добавить новое правило или изменить вес фактора было страшно. Ошибка в одном условии могла привести к тому, что мы выдали бы кредит мошеннику или отказали хорошему клиенту.
Когда мы переписывали это на Kotlin, мы применили два подхода, о которых я говорил сегодня:
Мы заменили лестницу
if-elseнаwhenбез аргумента. Каждое правило стало одной строкой вwhen, вызывающей отдельную функцию расчета.Для проверок на вхождение (например, возраст в диапазоне 25–40) мы использовали
in 25..40. Код стал читаться как техническое задание.
В итоге:
Размер метода сократился на порядок.
Сократилось время на код‑ревью.
А главное — мы нашли пару багов в старой логике (один
else ifбыл не на том месте), которые жили в проде годами. Компилятор Kotlin, конечно, не нашел бы логическую ошибку, но код стал настолько прозрачным, что ошибки бросились в глаза сами.
Это и есть сила выразительного синтаксиса.
Что дальше?
Мы разобрали мозг программы — условия и циклы. Теперь вы можете писать осмысленные алгоритмы. Но чтобы код не превращался в полотно, нужно учиться группировать действия. В следующей статье мы поговорим о функциях — как создавать свои строительные блоки и не повторяться.
Весь код из этой статьи доступен в моём репозитории на GitHub

Пишете на Kotlin, но в реальных задачах начинаете «плыть»: условия разрастаются, логика ломается, код становится трудно читать и менять?
Вам нужно не знать синтаксис, а уверенно писать предсказуемый и поддерживаемый код под реальные кейсы. Курс «Kotlin Developer. Basic» закрывает эту задачу: систематизирует базу и учит применять её так, чтобы код выдерживал рост сложности, а не превращался в спагетти.
Если хотите расти в Kotlin не урывками, а по понятной траектории — в OTUS есть каталог курсов по программированию, которые помогают перейти от базы к более уверенной практике.
Серия статей «Kotlin для новичков»:
