Почему в Kotlin у List нет методов add и remove, а у Map — put?
Короткий ответ: разница между изменяемыми и неизменяемыми коллекциями
В Kotlin коллекции разделены на два типа: изменяемые (mutable) и неизменяемые (immutable/read-only). Это не баг, а осознанное дизайнерское решение, которое делает код безопаснее и предсказуемее.
Функции listOf() и mapOf() создают неизменяемые коллекции. У них нет методов add, remove, put, потому что они не предназначены для изменения. Это гарантирует, что коллекция останется той же самой на всём протяжении её использования.
Как правильно: используйте mutable-версии
Если вам нужно изменять коллекцию, используйте mutableListOf(), mutableMapOf() и т.д.:
val mutableList = mutableListOf(1, 2, 3)
mutableList.add(4) // Работает
mutableList.removeAt(0) // Работает
val mutableMap = mutableMapOf("a" to 1, "b" to 2)
mutableMap.put("c", 3) // Работает
// Или более идиоматичный способ:
mutableMap["d"] = 4
Почему это важно?
- Безопасность потоков: неизменяемые коллекции можно безопасно передавать между потоками — никто случайно их не изменит.
- Предсказуемость: если функция принимает
List<Int>, вы знаете, что она не испортит вашу коллекцию. - Функциональный стиль: Kotlin поощряет работу с данными через трансформации (map, filter и т.д.), а не мутацию.
Как работать с неизменяемыми коллекциями, если нужно "добавить" элемент?
Вместо мутации используйте операторы + и -, которые создают новую коллекцию:
val original = listOf(1, 2, 3)
val newList = original + 4 // [1, 2, 3, 4]
val smallerList = original - 2 // [1, 3] — удаляет первое вхождение 2
val map = mapOf("a" to 1, "b" to 2)
val newMap = map + ("c" to 3) // {"a":1, "b":2, "c":3}
val withoutA = map - "a" // {"b":2}
Исходная коллекция original остаётся неизменной — это ключевой принцип.
Совет для новичков
Начинайте с listOf и mapOf по умолчанию. Переходите на mutableListOf только когда точно знаете, что изменение необходимо. Со временем вы привыкнете к функциональному стилю — это сделает ваш код чище и надёжнее.
Полная иерархия:
Iterable→Collection→List/SetMutableIterable→MutableCollection→MutableList/MutableSetMapиMutableMap— отдельное семейство
Альтернативный взгляд: используйте функции-расширения для удобства
Если вам часто нужно "добавить" элемент в неизменяемый список, можно написать свою функцию-расширение:
fun <T> List<T>.with(element: T): List<T> = this + element
fun <T> List<T>.without(element: T): List<T> = this - element
// Использование:
val list = listOf(1, 2, 3)
val updated = list.with(4) // [1, 2, 3, 4]
val removed = list.without(2) // [1, 3]
Также помните, что toMutableList() и toMutableMap() позволяют легко конвертировать неизменяемую коллекцию в изменяемую, если это нужно на короткое время:
val immutable = listOf(1, 2, 3)
val mutable = immutable.toMutableList()
mutable.add(4)
val backToImmutable = mutable.toList() // снова неизменяемый
Но старайтесь избегать частых конвертаций — это создаёт лишние копии и может снижать производительность. Лучше сразу выбирать правильный тип коллекции под задачу.
Ответов пока нет.
Войдите чтобы оставить ответ