Константы в Kotlin: правильные способы объявления и использования
Основные способы объявления констант в Kotlin
В Kotlin есть два основных подхода: val и const val. Они отличаются тем, когда и как вычисляются значения. Давайте разберёмся по порядку.
1. const val — настоящие константы времени компиляции
const val работает только с примитивами (Int, Long, Double, Boolean, Char) и строками (String). Значение должно быть известно на этапе компиляции. Такие константы встраиваются прямо в байт-код — как в Java static final.
// Верхнеуровневая константа (рекомендуется)
const val DEFAULT_TIMEOUT_MS = 5000L
const val APP_NAME = "MyApp"
// Внутри object (аналог статического класса)
object AppConstants {
const val BASE_URL = "https://api.example.com"
const val MAX_RETRIES = 3
}
// Внутри companion object (если константа логически связана с классом)
class NetworkClient {
companion object {
const val DEFAULT_PORT = 8080
}
}
2. val — константы времени выполнения (ленивые или вычисляемые)
val — это read-only переменная. Она может быть инициализирована в рантайме, например, результатом функции или сложным выражением.
// Вычисляется при первом обращении
val currentTime: Long get() = System.currentTimeMillis()
// Ленивая инициализация
val heavyConfig: Config by lazy {
loadConfigFromFile()
}
// Константа, которая не встраивается в код (без const)
val PI_APPROX = 3.14159 // не const — не будет встроена компилятором
3. Где хранить константы — лучшие практики
- Верхнеуровневые константы (в отдельном файле
Constants.kt) — самый идиоматичный способ для Kotlin. Просто пишитеconst valвне класса. - Внутри
object— если констант много и они логически сгруппированы (например,ApiEndpoints,DatabaseKeys). - Внутри
companion object— если константы тесно связаны с классом (например, порт по умолчанию для NetworkClient). - Избегайте хранения констант прямо внутри класса без companion — тогда каждая копия класса будет иметь свою копию переменной.
4. Пример сравнения Java vs Kotlin
// Java
public class Config {
public static final int MAX_CONNECTIONS = 10;
public static final String API_KEY = "12345";
}
// Kotlin — эквивалент
object Config {
const val MAX_CONNECTIONS = 10
const val API_KEY = "12345"
}
// Или ещё более идиоматично — на верхнем уровне
const val MAX_CONNECTIONS = 10
const val API_KEY = "12345"
5. Когда использовать const val, а когда просто val?
const val— когда значение известно на этапе компиляции И это примитив/строка. Используйте всегда, когда возможно — это даёт производительность (встраивание) и безопасность.val— когда значение вычисляется в рантайме (например,val uuid = UUID.randomUUID()), или когда это не примитив/строка (например, список, объект).const valНЕЛЬЗЯ использовать для:val list = listOf(1,2,3),val date = Date(),val config = MyConfig().
Итог: рекомендованный подход
// Файл Constants.kt
const val DEFAULT_TIMEOUT = 30_000L
const val API_VERSION = "v2"
// Файл NetworkConfig.kt (если нужно сгруппировать)
object NetworkConfig {
const val BASE_URL = "https://api.example.com"
const val RETRY_COUNT = 3
}
// В классе — только если логически принадлежит классу
class UserRepository {
companion object {
const val TABLE_NAME = "users"
}
}
Этот подход считается идиоматичным для Kotlin, не требует создания лишних объектов и даёт максимальную производительность.
<<Альтернативный подход: использование аннотации @JvmField и константы в интерфейсах
Если вы работаете в гибридном проекте Java + Kotlin или хотите сохранить совместимость с Java-кодом, можно использовать аннотацию @JvmField для создания статических полей:
// Kotlin — создаст статическое поле в Java
class MyClass {
companion object {
@JvmField
val MY_CONST = "value" // Без const, но @JvmField делает его static final
}
}
// Java-код будет обращаться: MyClass.MY_CONST
Ещё один вариант — использовать interface для хранения констант (это старый Java-паттерн, но в Kotlin тоже работает):
interface AppConstants {
companion object {
const val MAX_SIZE = 100
const val DEFAULT_NAME = "default"
}
}
// Использование
class MyActivity : AppConstants {
fun show() {
println(MAX_SIZE) // доступно через интерфейс
}
}
Минусы: такой подход считается устаревшим и неидиоматичным для чистого Kotlin. Лучше использовать верхнеуровневые константы или объекты. Однако если вам нужно, чтобы константы были видны из Java как static final поля, @JvmField может быть полезен.
Важно: без const val и без @JvmField поля в companion object будут доступны через геттер, что чуть медленнее и не является настоящей константой времени компиляции.
Ответов пока нет.
Войдите чтобы оставить ответ