Урок по треку Kotlin 6 мин

Основы Kotlin за 6 минут

val и var, типы, if и when как выражения, строки, диапазоны и равенство.

Kotlin компилируется в байткод JVM (а ещё в JS, Wasm и нативный код), полностью совместим с Java и с 2019 года считается основным языком Android. На собесе по основам проверяют не синтаксис, а понимание: что такое выражение, как работает равенство, чем val отличается от неизменяемости.

val и var

val name = "Kotlin"   // ссылку нельзя переназначить
var count = 0          // можно
count += 1

val запрещает переприсваивание, но не делает объект неизменяемым: val list = mutableListOf(1) позволяет list.add(2). Правило хорошего тона: по умолчанию val, var только когда действительно нужно.

const val это константа времени компиляции: только примитивы и String, только на верхнем уровне, в object или companion object. Значение подставляется в место использования.

Типы

Тип выводится сам, но он статический: val x = 1 навсегда Int. Числа: Byte, Short, Int, Long, Float, Double. Неявных расширяющих преобразований нет:

val i: Int = 1
val l: Long = i          // ошибка компиляции
val l2: Long = i.toLong() // так можно

Под капотом Int компилируется в примитив int, а Int? или Int внутри List<Int> в объект Integer (boxing). Есть беззнаковые UInt, ULong. Any это корень иерархии (как Object), Unit это «ничего полезного» (как void, но настоящий объект), Nothing это тип выражения, которое никогда не завершается нормально (throw, TODO()).

Всё, что можно, это выражение

if, when и try возвращают значение, поэтому тернарного оператора нет:

val max = if (a > b) a else b

val label = when (code) {
    200, 204 -> "ok"
    in 400..499 -> "client error"
    else -> "other"
}

val n = try { s.toInt() } catch (e: NumberFormatException) { 0 }

when без аргумента заменяет цепочку if-else. Если when используется как выражение, ветка else обязательна, кроме случаев, когда компилятор видит все варианты (enum, sealed, Boolean).

Строки и шаблоны

val user = "Аня"
println("Привет, $user! Длина: ${user.length}")
val json = """
    {"name": "$user"}
""".trimIndent()

Сырые строки в тройных кавычках не обрабатывают \n и удобны для регулярок и JSON.

Диапазоны и циклы

for (i in 1..5) {}          // 1, 2, 3, 4, 5
for (i in 0 until n) {}     // 0..n-1, то же что 0..<n
for (i in 10 downTo 0 step 2) {}
for ((index, value) in list.withIndex()) {}

Классического for (int i = 0; ...) нет. repeat(3) { } выполняет блок три раза.

Равенство

  • == это структурное равенство, вызывает equals и безопасно к null;
  • === это ссылочное равенство (тот же объект).
val a = "hi"
val b = String("hi".toCharArray())
println(a == b)   // true
println(a === b)  // false

Частая ловушка с упакованными числами: val x: Int? = 1000; val y: Int? = 1000; x === y может быть false, потому что это разные объекты Integer (кеш JVM покрывает только -128..127).

Функции верхнего уровня

В Kotlin функции и свойства не обязаны жить в классе. Файл Utils.kt с функцией fun hello() компилируется в класс UtilsKt со статическим методом. Точка входа fun main() тоже функция верхнего уровня.

Частые ошибки

  • Считать, что val делает коллекцию неизменяемой.
  • Ждать неявного Int → Long, как в Java.
  • Путать == и ===.
  • Писать if с return в каждой ветке вместо выражения.
  • Использовать 1..n в цикле по индексам и выходить за границу: нужен until или indices.

Что спросят на собесе

  • Чем val отличается от const val и от неизменяемого объекта?
  • Чем == отличается от ===?
  • Что такое Unit, Nothing и Any?
  • Почему в Kotlin нет тернарного оператора?
  • Когда Int превращается в объект на JVM?

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.