Отладка Kotlin кода: продвинутые техники и инструменты для профи

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

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

Начать курс

Почему отладка Kotlin — это искусство, а не рутина?

Представьте: вы пишете элегантный код на Kotlin, используете корутины, null-безопасность и extension-функции. Всё выглядит идеально, пока приложение не падает с NullPointerException в самом неожиданном месте. Или ещё хуже — корутина просто «засыпает» навсегда, не оставляя следов. Знакомо?

Отладка Kotlin кода — это не просто поиск багов. Это умение «подсматривать» за работой вашего приложения в реальном времени, понимать, как работают корутины, и быстро находить узкие места. В этой статье мы разберём продвинутые техники отладки Kotlin, которые сэкономят вам часы нервов и сделают код стабильнее.

Базовые инструменты отладки Kotlin в IntelliJ IDEA

IntelliJ IDEA — это не просто IDE, это настоящий швейцарский нож для Kotlin-разработчика. Давайте начнём с того, что лежит на поверхности, но часто используется неправильно.

Точки останова: больше, чем просто пауза

Обычная точка останова (line breakpoint) — это классика. Но Kotlin предлагает гораздо больше:

  • Conditional breakpoints — срабатывают только при выполнении условия. Например, остановиться, когда userId == 42.
  • Exception breakpoints — ловят исключения до того, как они упадут в лог.
  • Method breakpoints — срабатывают на входе и выходе из функции. Идеально для отладки сложных цепочек вызовов.

Пример настройки conditional breakpoint:

fun processOrder(order: Order) {
    // Ставим breakpoint и добавляем условие: order.amount > 1000
    val discount = calculateDiscount(order.amount)
    // ...
}

Просто кликните правой кнопкой мыши по точке останова и введите условие. Экономит кучу времени!

Отладка корутин: заглядываем внутрь async-мира

Корутины — это мощно, но отладка может превратиться в кошмар. IntelliJ IDEA (начиная с версии 2020.3) предлагает Coroutines Debugger. Он показывает:

  • Состояние каждой корутины (Active, Suspended, Completed).
  • Стек вызовов для каждой корутины.
  • Значения локальных переменных внутри корутины.
import kotlinx.coroutines.*

fun main() = runBlocking {
    val job1 = launch {
        delay(1000)
        println("Job 1 done")
    }
    val job2 = launch {
        delay(500)
        println("Job 2 done")
    }
    // Поставьте breakpoint здесь и посмотрите вкладку "Coroutines"
    job1.join()
    job2.join()
}

Совет: включите опцию Show coroutines в панели отладки — это спасёт вас от головной боли с асинхронным кодом.

Продвинутые техники: отладка без боли

Теперь перейдём к техникам, которые отличают новичка от профи.

Логирование как первый эшелон обороны

Не всегда можно поставить точку останова (например, в продакшене). Тут на помощь приходит логирование. Но не просто println(), а осмысленное логирование.

import org.slf4j.LoggerFactory

private val log = LoggerFactory.getLogger(MyService::class.java)

fun fetchUserData(userId: String): User? {
    log.debug("Fetching user data for userId: {}", userId)
    return try {
        val user = repository.findById(userId)
        log.info("User found: {}", user?.name)
        user
    } catch (e: Exception) {
        log.error("Failed to fetch user: {}", userId, e)
        null
    }
}

Используйте уровни логирования: TRACE для деталей, DEBUG для отладки, INFO для важных событий. И никогда не оставляйте println() в продакшене — это моветон.

Профилирование памяти: охота за утечками

Kotlin, благодаря JVM, подвержен утечкам памяти. Используйте встроенный Profiler в IntelliJ IDEA Ultimate. Он покажет:

  • Количество объектов в куче.
  • Ссылки на объекты (чтобы понять, кто держит объект).
  • GC activity (сборку мусора).

Типичный сценарий: вы забыли отменить корутину, и она держит ссылку на Activity. Profiler покажет это в виде Retained Size. Просто сделайте snapshot и сравните до и после действия.

Unit-тесты как отладка наоборот

Написание тестов — это тоже форма отладки. Вы проверяете гипотезы о поведении кода. Используйте JUnit 5 с Kotlin:

import org.junit.jupiter.api.Test
import kotlin.test.assertEquals

class CalculatorTest {
    @Test
    fun `addition should work correctly`() {
        val result = Calculator.add(2, 3)
        assertEquals(5, result)
    }
}

Пишите тесты до того, как нашли баг. Это называется TDD (Test-Driven Development). И да, это работает — проверено тысячами разработчиков.

Инструменты, которые стоит держать под рукой

IntelliJ IDEA — это база, но есть и другие инструменты, которые облегчат отладку Kotlin.

Kotlin REPL: песочница для экспериментов

Встроенный REPL (Read-Eval-Print Loop) позволяет быстро проверить кусок кода без компиляции всего проекта. Нажмите Tools → Kotlin → Kotlin REPL. Идеально для проверки lambda-выражений или работы с коллекциями.

// В REPL
val numbers = listOf(1, 2, 3, 4, 5)
numbers.filter { it % 2 == 0 }.map { it * 2 }
// Результат: [4, 8]

Kotlin Debugger в командной строке

Если вы работаете без IDE (например, на сервере), используйте Kotlin Script с флагом -Xdebug:

kotlin -J -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 myScript.kts

Затем подключитесь через IntelliJ IDEA к удалённой JVM через Remote JVM Debug. Это спасёт вас, когда баг воспроизводится только на сервере.

Типичные ошибки в Kotlin и как их отлавливать

Давайте разберём три самых частых сценария, которые валят Kotlin-код.

NullPointerException (несмотря на null-безопасность)

Да, Kotlin обещал нам безопасность, но if вы используете !! — вы сами напрашиваетесь. Как отловить?