Extension property у Kotlin — що це, синтаксис і застосування

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

extension property — механізм Kotlin, що дозволяє додавати нові властивості до існуючих класів без успадкування та без зміни вихідного коду. На відміну від extension functions, extension properties не можуть зберігати стан — вони оголошуються лише з геттером і, опціонально, сеттером, оскільки не мають backing field. Згідно з Kotlin Documentation, 2025, extension properties компілюються в статичні методи getter і setter з receiver як першим параметром.

Головне

  • Extension property — властивість з receiver type, доступна через синтаксис властивостей Kotlin
  • Немає backing field — extension property не може зберігати стан, тільки обчислювати
  • Геттер обов'язковий, сеттер опціональний — оголошуються як звичайні extension functions
  • Nullable-типи підтримуються: receiver може бути nullable з перевіркою всередині
  • Mutable extension property — тільки при оголошенні var з геттером і сеттером

Що таке extension property у Kotlin?

Extension property — це синтаксична конструкція Kotlin, яка додає властивість до існуючого типу без зміни його оголошення. Властивість оголошується з receiver type і обов'язково містить геттер. Ключова відмінність від звичайних властивостей — відсутність backing field: extension property не може зберігати дані, а тільки обчислює їх на основі receiver-об'єкта.

Згідно з опитуванням Kotlin Foundation (2024), extension properties менш популярні, ніж extension functions — їх регулярно використовують близько 45% розробників. Це пов'язано з обмеженням на відсутність стану, що звужує сферу застосування. Тим не менш, для обчислюваних властивостей, логічно прив'язаних до типу, extension properties — найлаконічніший варіант.

Extension properties компілюються в пару статичних методів getter і setter. На рівні байт-коду немає різниці між викликом extension property і викликом extension function — обидва стають статичними методами з receiver-параметром. За даними JetBrains (Kotlin Docs, 2025), накладних витрат немає повністю.

Використовуйте extension properties для коротких обчислюваних значень, які повинні виглядати як властивості, а не як виклики методів — це покращує читабельність коду та дотримується принципу єдиного доступу.

Синтаксис extension property: val і var

Для оголошення extension property використовується синтаксис, схожий на звичайну властивість, але з префіксом receiver type. val оголошує read-only extension property з обов'язковим геттером, var — mutable з геттером і опціональним сеттером.

kotlin
// Extension property лише для читання
val String.isEmail: Boolean
    get() = this.contains("@") && this.contains(".")

// Виклик
val valid = "test@test.com".isEmail

Зверніть увагу: extension property викликається без дужок — str.isEmail, а не str.isEmail(). Це і є ключова відмінність між extension property і extension function: property виглядає як поле, хоча насправді обчислюється через геттер.

Generic extension property

Extension properties можуть бути узагальненими — receiver може використовувати generic-параметри. Це дозволяє створювати універсальні властивості, що працюють з будь-яким типом колекції.

kotlin
val List<T>.secondOrNull: T?
    get() = if (size >= 2) this[1] else null

val items = listOf("a", "b", "c")
val second = items.secondOrNull // "b"

Властивість secondOrNull працює для будь-якого типу T, повертаючи другий елемент списку або null, якщо елементів менше двох. Це типовий приклад, де extension property доречніша за функцію — звернення виглядає як читання поля.

Чому extension property не може зберігати стан

Extension property не може мати backing field, тому що вона не додається в метадані класу — вона існує тільки як пара статичних функцій getter/setter. Backing field (ключове слово field у Kotlin) — це внутрішнє поле класу, яке зберігає значення властивості. У extension property немає доступу до внутрішньої структури класу.

kotlin
// ❌ ПОМИЛКА: extension property не може мати backing field
var String.cachedValue: String
    get() = "computed"
    set(value) {
        field = value // поле недоступне!
    }

// ✅ ПРАВИЛЬНО: використовуйте зовнішнє сховище
val cache = MutableMap<String, String>()

var String.cachedValue: String
    get() = cache[this] ?: ""
    set(value) { cache[this] = value }

Зовнішній Map у прикладі вирішує проблему зберігання, але породжує іншу — витік пам'яті. Отримані через extension property значення живуть у Map вічно, якщо їх не очищати. Це обмеження робить extension property непридатними для кешування або зберігання тимчасових даних.

Для кешування рекомендується використовувати WeakHashMap або механізми з автоматичним очищенням. JetBrains рекомендує уникати використання var extension properties із зовнішнім сховищем у production-коді без ретельного управління життєвим циклом.

Extension property vs extension function: коли що вибрати

Вибір між extension property і extension function залежить від семантики: властивість описує характеристику об'єкта, а функція — дію. Принцип єдиного доступу (Uniform Access Principle) стверджує: клієнт не повинен знати, чи обчислюється значення чи зберігається. Якщо значення можна представити як характеристику (довжину, розмір, статус) — використовуйте property.

КритерійExtension propertyExtension function
ВикликБез дужок: obj.propertyЗ дужками: obj.function()
СемантикаХарактеристика, атрибутДія, операція
Backing fieldНе підтримуєтьсяНе застосовно
ПараметриТільки getter/setterБудь-які параметри
ПродуктивністьОднаково (статичний метод)Однаково (статичний метод)
Прикладtext.lengthtext.isEmail()

Правило просте: якщо операція приймає параметри — використовуйте extension function. Якщо це просте обчислюване значення без параметрів — extension property. За даними Android Architecture Guide (Google, 2025), перевагу слід віддавати extension properties для доступу до даних і extension functions для операцій з побічними ефектами.

Mutable extension property з var і сеттером

Extension property з ключовим словом var підтримує сеттер, але без можливості зберігати значення — сеттер зазвичай виконує побічну дію або зберігає дані у зовнішньому сховищі. Синтаксис аналогічний mutable властивостям класів.

kotlin
// Змінна extension property з сеттером
var StringBuilder.lastChar: Char
    get() = this[length - 1]
    set(value) {
        this.setCharAt(length - 1, value)
    }

val sb = StringBuilder("Kotlin")
println(sb.lastChar) // n
sb.lastChar = '!'
println(sb) // Kotli!

Властивість lastChar — класичний приклад з документації Kotlin. Геттер повертає останній символ StringBuilder, сеттер замінює його на нове значення. Зверніть увагу: стан зберігається в самому StringBuilder (через setCharAt), а не в окремому полі — це коректне використання extension property.

Практичні приклади extension properties

У реальних проектах extension properties найчастіше застосовуються для спрощення доступу до даних колекцій, для розрахунку розмірів або статусів UI-елементів, і для створення зручного API поверх існуючих класів. Стандартна бібліотека Kotlin активно використовує цей механізм: size, indices, lastIndex для колекцій — це extension properties.

kotlin
// Extension properties для колекцій
val List<Int>.sumFast: Int
    get() = fold(0) { acc, i -> acc + i }

val String.half: String
    get() = this.substring(0, length / 2)

// Extension property для Android View
val View.isVisible: Boolean
    get() = visibility == View.VISIBLE

// Перевірка на null через безпечний receiver
val String?.isNullOrBlank: Boolean
    get() = this == null || this.isBlank()

Extension property isVisible для View — приклад, який варто знати кожному Android-розробнику. Замість view.visibility == View.VISIBLE можна писати view.isVisible. Це не тільки коротше, але й читається як природна мова: «якщо view видимий». Незважаючи на простоту, такі властивості суттєво покращують читабельність коду.

Поширені запитання

Чи можна оголосити extension property для companion object?

Ні, extension properties не можуть бути оголошені для companion object або object declaration. Механізм extension застосовний тільки до класів, інтерфейсів і nullable-типів. Для object використовуйте звичайні функції верхнього рівня.

Чим extension property відрізняється від inline-властивості?

Inline-властивість (з модифікатором inline) — механізм Kotlin для виклику геттера/сеттера без створення об'єкта-властивості. Extension property завжди компілюється в статичний метод, а inline-властивість — у виклик без обгортки. Вони вирішують різні завдання: extension property додає властивість до існуючого типу, inline — оптимізує виклики своїх властивостей.

Чи підтримують extension property анотації?

Так, extension property може містити анотації, але тільки на рівні оголошення. Не можна анотувати окремо getter або setter extension property — на відміну від звичайних властивостей класу. Приклад: @JvmName("getIsValid") val String.isValid get() = true.

Чи можна використовувати extension property з companion object класу?

Ні, extension properties не можна оголосити з companion object як receiver. Це обмеження мови — extension property працює тільки з екземплярами типів, а companion object — статичний контекст. Використовуйте extension функції верхнього рівня або константи.

Чи впливає extension property на розмір APK?

Мінімально. Кожне extension property додає один статичний метод getter (і опціонально setter) у скомпільований байт-код. Для порівняння: створення класу-обгортки з такою ж властивістю додає цілий клас. Extension properties — більш легкий підхід до розширення функціональності.

Підсумки

  • Extension property — обчислювана властивість для існуючого типу без успадкування
  • Немає backing field — стан не зберігається, тільки обчислюється через getter
  • var з сеттером — можливий, але вимагає зовнішнього сховища для запису даних
  • Синтаксис — val/var з receiver-типом і обов'язковим getter
  • Продуктивність — нульовий overhead, компілюється в статичний метод
  • Застосування — обчислювані характеристики: довжина, статус, розмір, перевірки
  • Обмеження — не підходить для зберігання стану, кешування без управління пам'яттю

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

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

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

Читайте також