Kotlin: List vs Array — битва типов данных, которую нужно знать

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Kotlin: List vs Array — в чём подвох?

Если вы пишете на Kotlin хотя бы неделю, вы наверняка сталкивались с вопросом: «А почему я не могу просто использовать Array везде? Зачем мне эти List и MutableList?»

Этот вопрос — один из самых популярных на Stack Overflow. И не зря. На первый взгляд, и список, и массив хранят элементы, к ним можно обращаться по индексу, их можно перебирать. Но копните глубже — и вы обнаружите фундаментальные различия, которые влияют на производительность, безопасность кода и даже на то, как вы мыслите, проектируя архитектуру.

В этом туториале мы разложим по полочкам разницу между List и Array в Kotlin. Вы узнаете, когда использовать массив, а когда — список, и почему опытные разработчики почти всегда выбирают List.

1. База: что такое Array в Kotlin?

Array в Kotlin — это прямая проекция Java-массива. Это фиксированная последовательность элементов одного типа. Когда вы создаёте массив, вы сразу выделяете под него память. Изменить размер массива после создания нельзя.

// Создание массива
val numbers: Array<Int> = arrayOf(1, 2, 3, 4, 5)
println(numbers[0]) // 1
numbers[2] = 10     // можно менять значение
println(numbers[2]) // 10

Массивы в Kotlin — это mutable (изменяемые) по своей природе: вы всегда можете заменить элемент по индексу. Но вы не можете добавить новый элемент или удалить существующий. Размер зафиксирован навсегда.

Особенности Array:

  • Фиксированный размер — нельзя добавить или удалить элемент.
  • Изменяемое содержимое — можно перезаписывать элементы.
  • Производительность — максимальная, так как это прямой доступ к памяти.
  • Примитивные массивы — есть специальные типы: IntArray, ByteArray, FloatArray и т.д. Они работают без boxing-упаковки, что даёт прирост скорости.
// Примитивный массив — без boxing
val intArray: IntArray = intArrayOf(1, 2, 3, 4, 5)

2. База: что такое List в Kotlin?

List — это интерфейс из стандартной библиотеки Kotlin. В отличие от массива, список — это абстракция. Вы не знаете, как именно он хранит данные внутри (это может быть ArrayList, LinkedList или что-то ещё).

// Создание неизменяемого списка
val fruits: List<String> = listOf("apple", "banana", "cherry")
println(fruits[0]) // apple
// fruits[0] = "orange" // Ошибка компиляции!

Главная «фишка» Kotlin — разделение на read-only (List) и mutable (MutableList).

List (read-only):

  • Нельзя изменить содержимое (ни добавить, ни удалить, ни заменить).
  • Можно только читать.
  • Безопаснее для передачи данных между компонентами.

MutableList:

  • Можно добавлять, удалять, заменять элементы.
  • Динамический размер.
  • На практике чаще всего используется ArrayList под капотом.
val mutableFruits: MutableList<String> = mutableListOf("apple", "banana")
mutableFruits.add("orange")     // OK
mutableFruits.remove("banana")  // OK
mutableFruits[0] = "pear"       // OK

3. Ключевые отличия List vs Array

Давайте сведём всё в наглядную таблицу (в коде — в виде комментариев).

// 1. Изменяемость
val array = arrayOf(1, 2, 3)
array[0] = 99 // ✅ Работает

val list = listOf(1, 2, 3)
// list[0] = 99 // ❌ Ошибка компиляции

val mutableList = mutableListOf(1, 2, 3)
mutableList[0] = 99 // ✅ Работает

// 2. Размер
val fixedArray = arrayOf(1, 2, 3)
// fixedArray.add(4) // ❌ Такого метода нет

val dynamicList = mutableListOf(1, 2, 3)
dynamicList.add(4) // ✅ Размер увеличился

// 3. Тип элементов
val mixedArray: Array<Any> = arrayOf(1, "hello", 3.14) // ❌ Не рекомендуется
val mixedList: List<Any> = listOf(1, "hello", 3.14)    // Тоже не рекомендуется

// 4. Производительность
// Array быстрее при чтении/записи по индексу
// List (ArrayList) чуть медленнее, но гибче

// 5. Примитивные типы
val primitiveArray = IntArray(5) // Без boxing — быстро
val objectArray = Array<Int>(5) { 0 } // С boxing — медленнее
val listOfInts = listOf(1, 2, 3) // Тоже с boxing

4. Когда использовать Array?

Честно говоря, в повседневном коде на Kotlin массивы используются редко. Но есть сценарии, где они незаменимы:

  • Работа с JVM-библиотеками — если вы вызываете Java-метод, который принимает массив.
  • Высокопроизводительные вычисления — обработка аудио, видео, научные расчёты. Тут IntArray или FloatArray дают серьёзный выигрыш в скорости.
  • Varargs — функция с переменным числом аргументов (vararg) внутри работает как массив.
  • Аннотации — значения аннотаций должны быть массивами.
fun printAll(vararg items: String) {
    // items — это Array<String> внутри
    for (item in items) {
        println(item)
    }
}

printAll("a", "b", "c")

5. Когда использовать List?

В 90% случаев выбирайте List или MutableList. Вот почему:

  • Гибкость — динамический размер, методы filter, map, find и т.д.
  • Безопасность — неизменяемый List защищает данные от случайного изменения.
  • Совместимость с Kotlin-функциями — все коллекции Kotlin заточены под List.
  • Лучшая практика — в современном Kotlin принято использовать коллекции, а не массивы.
data class User(val name: String, val age: Int)

val users: List<User> = listOf(
    User("Alice", 25),
    User("Bob", 30)
)

// Филь                

Блоги

Рекомендаций по книгам