Топ ошибок начинающих Kotlin разработчиков: от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Топ ошибок начинающих Kotlin разработчиков: от А до Я

Kotlin — современный, лаконичный и безопасный язык, который стремительно завоевал сердца Android-разработчиков и backend-инженеров. Однако даже в таком дружелюбном языке новички часто совершают типовые ошибки, которые замедляют обучение и приводят к багам. В этой статье мы разберём самые распространённые проблемы — от неправильного понимания null safety до злоупотребления lateinit. Вы узнаете, как их избежать и писать чистый, эффективный код на Kotlin.

1. Игнорирование null safety и неправильная работа с nullable типами

Одна из главных фишек Kotlin — встроенная защита от NullPointerException. Но новички часто пытаются использовать Java-подход, что приводит к ошибкам.

Ошибка: Использование !! (non-null assertion) там, где это не нужно

Многие пишут:

fun getUserName(user: User?): String {
    return user!!.name // Если user == null — будет NPE
}

Лучше использовать безопасный вызов (?.) или элвис-оператор (?:):

fun getUserName(user: User?): String {
    return user?.name ?: "Гость"
}

Ошибка: Неверное использование lateinit var

Поле lateinit предназначено для ситуаций, когда вы точно знаете, что переменная будет инициализирована перед первым использованием (например, в Android в onCreate). Но если обратиться к lateinit до инициализации, вы получите UninitializedPropertyAccessException.

Совет: Используйте lateinit только с var и проверяйте свойство ::variable.isInitialized перед доступом.

2. Неправильное использование коллекций: изменяемые vs неизменяемые

Kotlin чётко разделяет List (только для чтения) и MutableList. Новички часто путают их, что приводит к ошибкам компиляции или неожиданному поведению.

Ошибка: Попытка изменить неизменяемый список

val list = listOf(1, 2, 3)
list.add(4) // Ошибка компиляции! listOf возвращает List, а не MutableList

Если вам нужна изменяемая коллекция, используйте mutableListOf:

val mutableList = mutableListOf(1, 2, 3)
mutableList.add(4) // Работает

Ошибка: Возврат MutableList из публичного API

Это нарушает инкапсуляцию. Лучше возвращать List:

// Плохо
fun getItems(): MutableList<String> = mutableListOf("a", "b")

// Хорошо
fun getItems(): List<String> = mutableListOf("a", "b").toList()

3. Злоупотребление companion object вместо top-level функций

В Kotlin нет статических методов, но есть companion object. Новички часто кладут туда всё подряд, хотя можно использовать более лаконичные top-level функции или свойства.

Пример ошибки:

class Utils {
    companion object {
        fun formatDate(date: Date): String { ... }
    }
}

// Вызов: Utils.formatDate(...)

Лучше вынести функцию на уровень файла:

// file: DateUtils.kt
fun formatDate(date: Date): String { ... }

// Вызов: formatDate(...)

Это делает код чище и не требует создания лишнего класса. Используйте companion object только для фабричных методов или констант, связанных с классом.

4. Непонимание sealed классов и when-выражений

Sealed классы — мощный инструмент для представления ограниченной иерархии типов. Однако новички часто забывают про else ветку или используют if-else вместо when, теряя все преимущества.

Ошибка: Использование else в when для sealed класса

sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
}

fun handleResult(result: Result) {
    when (result) {
        is Result.Success -> println(result.data)
        else -> println("Error") // Плохо: если добавится новый подкласс, компилятор не предупредит
    }
}

Правильный подход — перечислить все варианты:

fun handleResult(result: Result) {
    when (result) {
        is Result.Success -> println(result.data)
        is Result.Error -> println(result.message)
    } // Компилятор проверит, что все ветки покрыты
}

5. Игнорирование scope функций (let, apply, run, with, also)

Scope функции делают код более выразительным, но новички либо не используют их вовсе, либо применяют неправильно.

Ошибка: Путаница между apply и let

apply возвращает сам объект (контекст — this), а let возвращает результат лямбды (контекст — it).

// Плохо: используем let для конфигурации объекта
val person = Person().let {
    it.name = "John"
    it.age = 30
    it // Надо явно вернуть
}

// Хорошо: используем apply
val person = Person().apply {
    name = "John"
    age = 30
}

Запомните правило: используйте apply для настройки свойств объекта, let — для проверки на null и преобразования результата.

Заключение

Kotlin — язык, который прощает многие ошибки, но знание типовых граблей сэкономит вам часы отладки. Мы разобрали 5 ключевых проблем: неправильная работа с null safety, путаница в коллекциях, злоупотребление companion object, неверное использование sealed классов и scope функций. Практикуйтесь, читайте код опытных разработчиков и не бойтесь переписывать свои старые решения. Удачи в изучении Kotlin!

Блоги

Рекомендаций по книгам