Небольшая статья с рассказом о новом типе классов в Kotlin 1.5.
РЕКОМЕНДУЕМ:
Представь себе следующую ситуацию. Есть такой класс:
1 2 3 4 5 6 7 |
class Person( val firstName: String, val lastName: String, val age: Int, val siblings: Int, ... ) |
Банальнейший класс, аналоги которого создавал любой программист. Где‑то в коде также есть такая функция:
1 |
fun setPersonData(firstName: String, lastName: String, age: Int, siblings: Int) |
Пока все абсолютно нормально, но что, если ты просто перепутаешь порядок аргументов:
1 |
setPersonData("Smith", "John", 0, 24) |
В этом случае функция отработает абсолютно неправильно, а среда разработки не сделает ни единого предупреждения. К тому же если в будущем внутренний формат хранения данных изменится (в этом примере проблем нет, но в реальном коде ID типа Int может замениться, например, на текстовый UID), то перерабатывать придется весь код, работающий с функцией и классом.
Решить эти проблемы можно так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Person( val firstName: FirstName, val lastName: LastName, val age: Age, val siblings: Siblings, ... ) fun setPersonData(firstName: FirstName, lastName: LastName, age: Age, siblings: Siblings) setPersonData( FirstName("John"), LastName("Smith"), Age(24), Siblings(0), ) |
То есть обернуть простые типы данных в объекты. Но! Во‑первых, это неудобно, во‑вторых, постоянное создание объектов в итоге приведет к падению производительности.
Как раз здесь на сцену выходит value class. По сути, это класс с одним полем, например:
1 |
value class FirstName(val value: String) |
Однако, в отличие от обычного класса, value-класс инлайновый. Он не будет существовать в результирующем байт‑коде приложения. Компилятор развернет все value-классы и будет использовать вместо них сохраненные внутри значения.
Более того, value-класс может не просто хранить значение, но и валидировать его. Например:
1 2 3 4 5 6 7 |
value class Age( val value: Int, ) { init { require(value >= 0) { "age must be >= 0: '$value'" } } } |
Такой value-класс выбросит исключение IllegalArgumentException, если создать его с отрицательным значением.
Оригинальная статья на английском языке