Kotlin-специфіка в мобільній розробці: що це, які конструкції та як працює

Автор: IT Sectr Опубліковано: 2026-06-29 Час читання: 11 хв

Kotlin — основна мова для Android-розробки. За даними Google Android Docs (2025), понад 95% нових проєктів на Android використовують Kotlin. Розуміння специфіки Kotlin — data class, sealed class, корутини та scope functions — обов'язкова вимога для Android-розробника.

Головне

  • data class — автоматична генерація equals/hashCode/toString/copy/componentN. Для моделей даних. sealed class — обмежена ієрархія типів з перевіркою when.
  • Scope functions: let, run, with, apply, also. Різняться за контекстом (it vs this) та поверненням.
  • Корутини: launch (fire-and-forget), async (з результатом), runBlocking (міст), withContext (зміна Dispatcher).
  • lifecycleScope та viewModelScope — Lifecycle-aware корутини без ручного скасування.
  • reified — збереження типу в inline-функціях. lateinit/lazy — відкладена ініціалізація.

Класи (data class, sealed class, object, companion object)

Kotlin розширює концепції класів з Java. data class, sealed class, object та companion object — конструкції, яких немає в Java або вони реалізовані інакше.

data class vs sealed class

data class — клас, який автоматично генерує equals(), hashCode(), toString(), copy() та componentN(). Ідеально для моделей даних (DTO, Entity). Вимоги: мінімум один параметр primary constructor, val/var, не може бути open/sealed/inner. sealed class — клас з обмеженою ієрархією підкласів. Усі підкласи відомі на етапі компіляції та оголошені в тому ж файлі. when-вираз із sealed class не потребує else-гілки. sealed interface (Kotlin 1.9+) — те саме, що sealed class, але дозволяє множинне успадкування. object — синглтон, оголошується ключовим словом object (не class). Thread-safe лінива ініціалізація. companion object — статичні члени класу. Має ім'я (за замовчуванням Companion). Може реалізовувати інтерфейси та мати extension функції.

Тип Опис Застосування
data classАвтоматична генерація equals, hashCode, toString, copyМоделі даних, DTO, Entity
sealed classОбмежена ієрархія, перевірка whenСтани, Result, UI State
sealed interfacesealed class + множинне успадкуванняПодії, Дії (Kotlin 1.9+)
objectСинглтон (декларативний)Factory, Utility, Константи
companion objectСтатичні члени класуFactory Method, статичні константи
enum classПерелік з константамиСтани з фіксованим набором

data class — для 90% моделей. sealed class — для UI State та Result. object — для синглтонів. IT Sectr рекомендує sealed class для всіх станів екрану (Loading, Success, Error).

Sealed class на практиці

Sealed class — потужний інструмент для моделювання станів. Приклад: UiState<T> з підкласами Loading, Success(data: T), Error(message: String). when-вираз гарантує обробку всіх станів. Sealed interface — для подій (events) та дій (actions), де потрібна множинна імплементація. Value class (Kotlin 1.5+) — обгортка для одного значення без overhead. Використовується для типобезпечних ідентифікаторів: @JvmInline value class UserId(val id: String).

Функції (extension, inline, higher-order, scope functions)

Extension Function — додавання методу до існуючого класу без успадкування. fun String.isEmail(): Boolean. Extension Property — те саме для властивостей (без backing field). Inline Function — підстановка тіла функції в місце виклику — без overhead виклику. Використовується для higher-order функцій з лямбдами. Higher-Order Function — функція, яка приймає або повертає іншу функцію. Scope Functions — п'ять функцій для роботи з контекстом об'єкта: let, run, with, apply, also.

Scope Functions

let — контекст it, повертає lambda result. Використовується для null-safe викликів (?.let {}). apply — контекст this, повертає контекст. Для конфігурації об'єкта. run — контекст this, повертає lambda result. Для обчислень з контекстом. also — контекст it, повертає контекст. Для side effects (логування). with — не extension, контекст this, повертає lambda result. Для групи операцій над об'єктом. Lambda — анонімна функція. Destructuring Declaration — розпакування data class на змінні: val (name, age) = person.

Inline + reified

Inline function з reified — єдиний спосіб зберегти generic тип в JVM. Використовується для: типобезпечних білдерів (Gson.fromJson<T>()), перевірки типів (is T), отримання класу (T::class). Crossinline та Noinline — модифікатори для параметрів-лямбд в inline функціях. crossinline — забороняє non-local return, noinline — забороняє інлайн конкретної лямбди. IT Sectr рекомендує inline + reified тільки при роботі з типами, для звичайних higher-order функцій inline може збільшити розмір байткоду.

Корутини (Coroutine Builder, Dispatchers, Scope)

Корутини — легкі потоки для асинхронного програмування. Не блокують потік — призупиняються (suspend). suspend function — функція, яку можна призупинити без блокування потоку. Може викликатися тільки з корутини або іншої suspend функції.

CoroutineScope

CoroutineScope — область видимості корутин. Містить CoroutineContext (Job + Dispatcher). lifecycleScope — для Activity/Fragment (Lifecycle-aware). viewModelScope — для ViewModel (автоскасування при onCleared()). GlobalScope — глобальний (не використовувати в production — витоки пам'яті). Dispatchers: Dispatchers.Main (UI), Dispatchers.IO (мережа/диск), Dispatchers.Default (CPU-intensive), Dispatchers.Unconfined (не рекомендується). launch — запуск корутини: Job. async — запуск з результатом: Deferred<T>. runBlocking — блокуючий міст. withContext — зміна Dispatcher всередині suspend-функції.

kotlin
// Приклад корутин: завантаження даних в ViewModel
class MainViewModel : ViewModel() {
    private val _state = MutableStateFlow<UiState>(UiState.Loading)
    val state: StateFlow<UiState> = _state.asStateFlow()

    fun loadData() {
        viewModelScope.launch {
            _state.value = UiState.Loading
            try {
                val data = withContext(Dispatchers.IO) {
                    repository.fetchData()
                }
                _state.value = UiState.Success(data)
            } catch (e: Exception) {
                _state.value = UiState.Error(e.message)
            }
        }
    }
}

// Паралельні запити з async
suspend fun loadCombinedData(): CombinedData = coroutineScope {
    val users = async(Dispatchers.IO) { api.getUsers() }
    val posts = async(Dispatchers.IO) { api.getPosts() }
    CombinedData(users.await(), posts.await())
}

viewModelScope.launch — стандартний запуск корутини в ViewModel. withContext(Dispatchers.IO) — перемикання на IO-потік для мережевого запиту. Dispatchers визначають, на якому пулі потоків виконується корутина. IT Sectr рекомендує viewModelScope для ViewModel та lifecycleScope для Activity/Fragment.

Продвинуті можливості (reified, destructuring, lateinit/lazy)

reified — модифікатор типу в inline-функціях. Дозволяє використовувати тип: T::class, is T, as T. Без reified Generics в JVM стираються (type erasure). inline fun + reified — потужна комбінація для типобезпечних API. Destructuring Declaration — val (x, y) = point. Працює для data class та типів з componentN(). typealias — псевдонім типу: typealias Callback = (String) -> Unit. lateinit — відкладена ініціалізація var (для dependency injection). Потоконебезпечний. lazy — лінива ініціалізація val (thread-safe за замовчуванням). lazy(LazyThreadSafetyMode.NONE) — без синхронізації. Extension function та Extension property — додавання функціональності без успадкування. Kotlin — мова, де extension functions вирішують 90% завдань утиліт.

Delegated Properties

Delegated Properties — делегування getter/setter іншому об'єкту. Стандартні делегати: lazy, observable, vetoable, map. Кастомний делегат через getValue/setValue оператори. by — ключове слово делегування: val name by lazy { loadName() }. Delegated properties — основа для ViewModel делегатів (by viewModels()). IT Sectr рекомендує lazy для відкладеної ініціалізації та Delegates.observable для спостереження за змінами.

Фіча Опис Приклад
reifiedЗбереження generic типу в inlineinline fun <reified T> parse(): T
destructuringРозпакування data classval (name, age) = person
typealiasПсевдонім типуtypealias Orders = List<Order>
lateinitВідкладена var ініціалізаціяlateinit var adapter: Adapter
lazyЛінива val ініціалізаціяval config by lazy { load() }
delegatedДелегування властивостейvar x by Delegates.observable(0)

reified — для типобезпечних API. lazy — для відкладеного завантаження. delegated properties — для перевикористання логіки властивостей. IT Sectr рекомендує освоїти всі ці можливості для ефективної Kotlin-розробки.

Flow та StateFlow

Flow — холодний асинхронний потік даних в Kotlin. Емітить значення на вимогу колектора. StateFlow — гарячий Flow з єдиним поточним значенням. Використовується в ViewModel для UI State. SharedFlow — гарячий Flow для подій (one-shot events). flowOf, asFlow — створення Flow з колекцій. catch, retry, debounce — оператори. stateIn, shareIn — конвертація холодного Flow в гарячий. IT Sectr рекомендує StateFlow для UI State та SharedFlow для подій (Snackbar, навігація).

kotlin
class SearchViewModel : ViewModel() {
    private val _query = MutableStateFlow("")
    val suggestions: StateFlow<List<String>> = _query
        .debounce(300)
        .filter { it.length >= 2 }
        .flatMapLatest { repository.search(it) }
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())

    fun onQueryChanged(query: String) {
        _query.value = query
    }
}

Серіалізація (kotlinx.serialization, Parcelize)

kotlinx.serialization — бібліотека Kotlin для JSON-серіалізації. @Serializable — анотація. @SerialName — кастомне ім'я поля. Підтримує: JSON, CBOR, ProtoBuf. Parcelize — @Parcelize для Android Parcelable (без ручної реалізації). Gson vs Moshi vs kotlinx: kotlinx.serialization — Kotlin-first, compile-safe, без reflection. Moshi — анотації + codegen. IT Sectr рекомендує kotlinx.serialization для нових проєктів та Moshi для існуючих.

kotlin
@Serializable
data class ApiResponse<T>(
    val success: Boolean,
    @SerialName("data") val data: T? = null,
    val error: String? = null
)

@Serializable
data class User(
    val id: Int,
    val name: String,
    val email: String
)

// Десеріалізація
val json = Json { ignoreUnknownKeys = true }
val response = json.decodeFromString<ApiResponse<List<User>>>(jsonString)
println("Users: ${response.data?.size ?: 0}")

Часті запитання

В чому різниця між data class та sealed class?

data class — для даних (авто-генерація equals/hashCode/copy). sealed class — для ієрархії типів (перевірка в when). sealed interface — те саме з множинним успадкуванням.

Що таке scope functions в Kotlin?

let, run, with, apply, also. Різняться за контекстом (it vs this) та поверненням (result vs context). let — null safety, apply — конфігурація, also — side effects.

Що таке CoroutineScope та які бувають?

CoroutineScope — область корутин. lifecycleScope — для Activity, viewModelScope — для ViewModel. GlobalScope — не рекомендується.

Що таке reified в Kotlin?

reified — збереження типу в inline-функції. Дозволяє T::class та is T. Працює тільки з inline функціями.

Що таке coroutine builders: launch, async, runBlocking?

launch — без результату. async — з результатом (Deferred). runBlocking — блокуючий міст для main/test. withContext — зміна Dispatcher.

Підсумки

  • data class — для моделей. sealed class — для станів. object — для синглтонів.
  • Scope functions: let (null-safe), apply (конфігурація), run (обчислення), also (логування).
  • Корутини: launch (fire-and-forget), async (з результатом), withContext (зміна Dispatcher).
  • viewModelScope — стандарт для ViewModel. lifecycleScope — для Activity/Fragment.
  • reified — типобезпечні inline-функції. lateinit — DI, lazy — лінива ініціалізація.
  • Extension functions — додавайте функціональність без успадкування.
  • Dispatchers: Main (UI), IO (мережа/диск), Default (CPU). Вибирайте правильний.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект