ПрограммированиеAndroid разработчик

Опишите механизм работы коллекций в Kotlin: различия между List, MutableList, Set, MutableSet, Map, MutableMap. Какие подводные камни могут возникнуть при их использовании? Приведите примеры кода.

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Kotlin предлагает два типа коллекций: immutable (неизменяемые) и mutable (изменяемые).

  • List — неизменяемый список. Добавлять/удалять элементы нельзя.
  • MutableList — изменяемый список: можно добавлять и удалять элементы.
  • Set — неизменяемое множество (уникальные элементы).
  • MutableSet — изменяемое множество.
  • Map — ассоциативный массив (ключ-значение), неизменяемый.
  • MutableMap — изменяемый ассоциативный массив.

Пример кода:

val fruits: List<String> = listOf("Apple", "Banana", "Cherry") val mutableFruits: MutableList<String> = mutableListOf("Apple", "Banana") mutableFruits.add("Cherry") val fruitSet: Set<String> = setOf("Apple", "Banana") // Уникальность элементов val mutableFruitSet: MutableSet<String> = mutableSetOf("Apple", "Banana") mutableFruitSet.add("Cherry") val scores: Map<String, Int> = mapOf("Tom" to 80, "Jane" to 90) val mutableScores: MutableMap<String, Int> = mutableMapOf("Tom" to 80) mutableScores["Jane"] = 90

Тонкости:

  • Коллекции по умолчанию — неизменяемые.
  • Многие функции возврата списков из стандартной библиотеки возвращают List (а не MutableList).
  • При работе с коллекциями важно не изменять те, которые не задумывались для изменений.

Вопрос с подвохом.

Если у вас есть функция, принимающая List<T> как параметр, можете ли вы каким-либо образом изменить этот список внутри функции?

Ответ: Нет, если параметр типа List<T>, то внутри функции нельзя добавить/удалить элементы. Но если фактически передан MutableList<T>, его можно привести к этому типу (что привносит риск):

fun modifyList(list: List<String>) { if (list is MutableList) { list.add("Another") // Работает, если исходная коллекция изменяемая } }

Так делать не рекомендуется, так как нарушается контракт (List должен быть неизменяемым!).

Примеры реальных ошибок из-за незнания тонкостей темы.


История

В крупном проекте использовали функцию, принимающую List<Customer>, и пытались добавить в неё новый элемент внутри функции. Ошибка компиляции (add/clear/remove не определены для List) была обнаружена только при ревью, т.к. требовался именно изменяемый список для преобразования данных.


История

Коллекция была объявлена как MutableList, но передавалась в несколько потоков без синхронизации. В итоге возникали конкурирующие изменения, приводившие к "ConcurrentModificationException" и порче состояния списка. Ошибку искали долго, не приняли во внимание thread-safety.


История

В одном из сервисов для работы с результатами выборок из БД использовали mutableListOf, потом отдавали ссылку наружу. Сторонний код по ошибке очищал список. В результате до пользователя доходили пустые данные, т.к. ссылки не клонировались и mutable коллекции модифицировались за пределами слоя бизнес-логики.