В чем разница между List и Array в Kotlin? Когда что использовать?
Ключевое различие: неизменяемость размера и тип хранимых данных
Главное различие между Array и List в Kotlin — это неизменяемость размера у массива и тип хранимых данных. Массив имеет фиксированный размер, заданный при создании, а список может динамически расширяться (через MutableList). Но это только верхушка айсберга.
1. Массивы (Array) — низкоуровневый контейнер фиксированного размера
Array в Kotlin — это прямая обертка над JVM-массивом. Его размер никогда не меняется. Вы не можете добавить или удалить элемент — только заменить существующий по индексу.
// Создание массива
val arr = arrayOf(1, 2, 3) // Тип Array<Int>
arr[0] = 10 // ✅ Замена элемента
// arr.add(4) // ❌ Ошибка — такого метода нет
// arr.removeAt(0) // ❌ Ошибка
Для примитивных типов (Int, Double, Boolean и т.д.) Kotlin предоставляет специализированные массивы: IntArray, DoubleArray, CharArray и другие. Они хранят значения без упаковки в объекты (без boxing), что экономит память и повышает производительность.
val intArr = IntArray(5) { it * 2 } // [0, 2, 4, 6, 8] — без boxing
val objArr = Array<Int>(5) { it * 2 } // Каждый Int упакован в Integer (boxing)
2. Списки (List) — интерфейс для коллекций с динамическим размером
List — это интерфейс, представляющий упорядоченную коллекцию с произвольным доступом. Реализация по умолчанию — ArrayList (аналог Java). List сам по себе неизменяемый (read-only): вы не можете добавлять, удалять или заменять элементы.
val list = listOf(1, 2, 3) // List<Int>
// list[0] = 10 // ❌ Ошибка: List — read-only
val mutableList = mutableListOf(1, 2, 3) // MutableList<Int>
mutableList[0] = 10 // ✅ Можно заменить
mutableList.add(4) // ✅ Можно добавить
mutableList.removeAt(0) // ✅ Можно удалить
Для списков нет специализированных типов для примитивов (как IntList). Все элементы List<Int> будут упакованы в объекты Integer. Это сделано для единообразия работы с коллекциями.
3. Когда что использовать?
- Используйте Array (или IntArray), когда:
- Размер коллекции известен заранее и не изменится
- Вам критична производительность (например, научные расчеты, обработка сигналов)
- Работаете с большим количеством примитивов (миллионы чисел) —
IntArrayв разы экономичнееList<Int> - Взаимодействуете с Java-кодом, который ожидает массив
- Используйте List (или MutableList), когда:
- Размер коллекции может меняться (добавление/удаление элементов)
- Вам нужны удобные методы:
filter,map,find,anyи т.д. - Храните объекты (не примитивы) — разница в производительности незначительна
- Пишете общий код, который должен работать с разными реализациями (List — это интерфейс)
4. Пример сравнения производительности
// Array — быстро, но фиксированный размер
val array = IntArray(1_000_000) { it }
var sum = 0L
for (i in array.indices) {
sum += array[i]
}
// List — медленнее из-за boxing, но гибкий
val list = List(1_000_000) { it }
var sum2 = 0L
for (i in list.indices) {
sum2 += list[i] // Каждый it упаковывается в Integer
}
5. Итоговая таблица
| Характеристика | Array | List |
|---|---|---|
| Размер | Фиксированный | Динамический (MutableList) |
| Изменяемость | Только замена элементов | Read-only или mutable |
| Примитивы без boxing | Да (IntArray и др.) | Нет |
| Методы (filter, map) | Нет (только extension-функции) | Да (богатый API) |
| Производительность | Высокая | Средняя (из-за boxing) |
Совет: В 90% случаев в Kotlin используйте List / MutableList. К ним есть удобные функции из стандартной библиотеки, и код получается более идиоматичным. Массивы оставьте для низкоуровневых задач, работы с большими объемами примитивов или взаимодействия с Java/Android API.
Дополнение: vararg и сигнатуры функций
Еще одно важное различие — Array используется в Kotlin для передачи переменного числа аргументов (vararg). Если вы пишете функцию с vararg, Kotlin ожидает именно массив (или распакованные значения):
fun printAll(vararg strings: String) {
strings.forEach { println(it) }
}
// Вызов с массивом
val arr = arrayOf("a", "b", "c")
printAll(*arr) // Оператор * распаковывает массив
// Вызов со списком — не сработает
val list = listOf("a", "b", "c")
// printAll(*list) // ❌ Ошибка: список нельзя распаковать через *
printAll(*list.toTypedArray()) // ✅ Придется преобразовать
Также помните: Array<Int> и IntArray — это разные типы. Они не взаимозаменяемы:
val a: IntArray = intArrayOf(1, 2, 3)
val b: Array<Int> = arrayOf(1, 2, 3)
// a = b // ❌ Ошибка типа
Поэтому, если API ожидает IntArray (например, в Android для Bitmap.getPixels), используйте именно его, а не Array<Int>.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Алгоритмы и структуры данных на Java: полное руководство для начинающих