В чем разница между val и const val в Kotlin и когда использовать const val
Что проверяют
Понимаете ли вы, что одно вычисляется при выполнении, а второе подставляется при компиляции.
Как отвечать
val это неизменяемая ссылка, значение которой вычисляется во время выполнения. Может быть результатом вызова функции, может зависеть от других объектов, может иметь пользовательский геттер, может быть локальной переменной или свойством класса.
const val это константа времени компиляции. Значение известно компилятору, и он подставляет его прямо в места использования, никакого обращения к свойству во время выполнения не происходит.
Отсюда жёсткие ограничения const val:
- только примитивные типы и
String; - объявляется только на верхнем уровне файла, внутри
objectили вcompanion object. Локальной или свойством обычного класса быть не может; - инициализируется литералом или другой константой, вызов функции недопустим;
- не может иметь пользовательского геттера.
Когда брать const val:
- настоящие константы: ключи для
BundleиSharedPreferences, теги, имена событий аналитики, базовые адреса; - значения для аннотаций: аннотации принимают только константы времени компиляции, и обычный
valтуда просто не подставить; - выражения в
when: константа может быть меткой ветки.
Есть и заметная деталь для взаимодействия с Java: const val компилируется в статическое поле и доступен из Java напрямую, а val в companion object требует либо вызова геттера через Companion, либо аннотации @JvmField.
Обратная сторона подстановки: значение вшивается в вызывающий код. Если константа лежит в отдельной библиотеке и её поменяли, пользователь получит новое значение только после пересборки своего кода, а не после обновления библиотеки.
Где спотыкаются
Пытаются объявить const val внутри обычного класса.
Присваивают const val результат функции.
Считают val полностью неизменяемым, забывая, что объект по ссылке может меняться.
Не знают, что для аннотаций нужна именно константа времени компиляции.