В Kotlin под иммутабельностью обычно понимают невозможность изменить состояние объекта после его создания. Это достигается через использование val (неизменяемых) свойств, а также через создание классов с инициализацией только в конструкторе без методов, позволяющих менять внутренние данные.
Kotlin, в отличие от Java, предоставляет удобный механизм для создания immutable-классов через data class и такие коллекции как List, Set, Map (которые по умолчанию неизменяемые). Но важно понимать, что в Kotlin базовые коллекции иммутабельны только на уровне интерфейса, а сам объект коллекции может быть изменён, если привести к MutableList и т.п.
Пример правильной иммутабельности:
// Data class и val обеспечивают иммутабельность data class User(val name: String, val age: Int) val user = User(name = "Ivan", age = 30) // user.name = "Sergey" // COMPILATION ERROR
Пример кода с нарушением иммутабельности:
class User(var name: String, var age: Int) val user = User("Ivan", 30) user.name = "Sergey" // Изменение объекта возможно
Нюансы:
val полями не гарантирует полной иммутабельности, если поля — ссылочные типы и их внутреннее состояние меняется.val + неизменяемые типы (например, val scores: List<Int>).Являются ли объекты класса data class с только val свойствами полностью неизменяемыми (immutable)?
Ответ: Нет, если свойства – это изменяемые объекты (например, val items: MutableList<Int>), внутреннее состояние можно менять.
Пример:
data class Group(val members: MutableList<String>) val group = Group(mutableListOf("Tom", "Jerry")) group.members.add("Spike") // внутреннее состояние изменяется
История
В проекте использовался immutable
data classсvalсвойством типаMutableList. Один из разработчиков ждал, что объект нельзя будет изменить, однако другой разработчик добавил новые элементы в коллекцию. Это привело к неконсистентности данных и сложно выявимым багам, когда два потока параллельно изменяли общий список.
История
При передаче экземпляра класса с изменяемой коллекцией между слоями приложения один слой изменял содержимое, не уведомляя другой слой. Это вызвало ситуации, когда UI не знал о произошедших изменениях и работал с невалидными исходными данными.
История
Разработчик ошибочно полагал, что
Listв Kotlin всегда неизменяем. На самом деле под капотом использовалась реализация, переданная из Java (ArrayList), и попытка изменить список привела к неожиданной потере данных и багам при работе с базой.