Куда попадает новый экземпляр мапы после применения оператора плюс в Kotlin
Что проверяют
Понимаете ли вы, что + у Map в Kotlin ничего не меняет в исходной мапе, а копирует её, и во что именно копирует. Следом обычно спрашивают, чем map + pair отличается от map += pair и сколько это стоит на большой коллекции.
Как отвечать
Короткий ответ: результат попадает в новый объект в куче, а переменная слева от = получает ссылку на него. Исходная мапа не меняется.
Дальше детали, которые показывают знание стандартной библиотеки:
- тип результата: для непустой мапы
plusделаетLinkedHashMap(this)и кладёт туда новую пару, поэтому порядок вставки сохраняется, а наружу результат объявлен как read-onlyMap; - совпадение ключа: если ключ уже есть, в копии значение перезапишется, в оригинале останется старое;
- стоимость: копируются все элементы, то есть O(n) по времени и памяти на каждый вызов. В цикле это превращается в O(n²);
+=наvalсMutableMap: вызываетсяplusAssign, то есть обычныйputв ту же мапу, без копии;+=наvarсMap: разворачивается вmap = map + pair, создаётся новая мапа, и переменная переприсваивается;varсMutableMap: компилятор не может выбрать между двумя вариантами и выдаёт ошибку неоднозначности.
Для Android полезно связать это с состоянием экрана. В StateFlow или в Compose-состоянии новая мапа через + как раз правильный способ сообщить об изменении: они замечают только новое значение, а мутация той же MutableMap снаружи не видна. Если мапа большая и копий много, есть kotlinx.collections.immutable с PersistentMap, где новая версия делит структуру со старой.
Где спотыкаются
Говорят, что + «добавляет элемент в мапу». Это верно только для результата: оригинал не меняется, и вызов map + pair без присваивания просто выбрасывает новую мапу.
Собирают мапу в цикле через result = result + (k to v). На тысячах элементов это квадратичная сложность и лишняя работа для GC, здесь нужны buildMap, associate или одна mutableMapOf с put.
Считают read-only Map неизменяемой. Интерфейс только запрещает менять данные через эту ссылку, а под ним может лежать MutableMap, которую кто-то поменяет в другом месте.