В каких случаях использовать Map для данных
Что проверяют
Умеете ли вы выбрать структуру данных по операции, которая нужна, а не по привычке. В Android следом обычно спрашивают про память: чем ArrayMap и SparseArray отличаются от HashMap и когда их брать.
Как отвечать
Map нужен, когда главная операция это доступ по ключу, а не проход по порядку. Типичные случаи:
- поиск по идентификатору: быстро найти элемент по
id, не перебирая список. ДляHashMapэто O(1) в среднем; - группировка и подсчёт: в Kotlin
groupBy,associateByиgroupingBy { }.eachCount()собирают Map одной строкой; - кэш: для кэша с ограничением размера в Android есть готовый
LruCache, он построен наLinkedHashMapс порядком доступа; - уникальность по ключу: последняя запись с тем же ключом заменяет предыдущую.
Выбор реализации:
HashMap: порядок не гарантирован;LinkedHashMap: сохраняет порядок вставки. Важная деталь Kotlin:mutableMapOf()иmapOf()с несколькими парами возвращают именно его;TreeMap: сортировка по ключу, операции за O(log n);SparseArray,SparseIntArray: ключи типаIntбез упаковки в объекты, внутри бинарный поиск по массиву;ArrayMapиз androidx.collection: экономит память на небольших коллекциях, до сотен элементов. На больших работает медленнееHashMap.
Когда Map не нужен: данные для RecyclerView, где важен порядок и есть DiffUtil, лучше держать списком. В Compose изменяемое состояние в виде словаря хранят в mutableStateMapOf, иначе UI не узнает об изменениях.
Где спотыкаются
Используют как ключ объект с изменяемыми полями. Если поле data class поменялось после вставки, hashCode другой, и элемент больше не находится.
Держат в статическом Map или синглтоне ссылки на Activity, Context или View. Это классическая утечка памяти, и сам Map тут не виноват.
Пишут в обычный HashMap из нескольких потоков или корутин на Dispatchers.IO. Нужен ConcurrentHashMap или доступ через один поток.