Топ ошибок начинающих 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!