Kotlin MutableList: как создать пустой список и не сойти с ума

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

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

Начать курс

Вступление: Парадокс пустого списка в Kotlin

Представьте: вы пишете на Kotlin, и вам нужно создать список, который будет динамически пополняться. Вы знаете, что List — это неизменяемая коллекция, а MutableList — то, что доктор прописал. Но как только вы пишете val list = MutableList(), компилятор выдаёт ошибку. Знакомо?

Этот вопрос — один из самых популярных на Stack Overflow среди новичков в Kotlin (и не только). Тысячи разработчиков спотыкаются об одну и ту же граблю: как правильно инициализировать пустой MutableList? Казалось бы, мелочь, но без этого не работает ни один динамический алгоритм.

В этой статье мы разберём все легальные способы создать пустой изменяемый список в Kotlin. От простых лайфхаков до продвинутых техник. Вы узнаете, почему mutableListOf() — ваш лучший друг, а ArrayList() — старый, но надёжный товарищ. Поехали!

1. Почему просто MutableList() не работает?

Давайте сразу развеем миф. Если вы попробуете написать:

// Ошибка компиляции!
val list = MutableList()

Компилятор справедливо возмутится. Почему? Потому что MutableList — это интерфейс, а не конкретный класс. Интерфейс нельзя инстанцировать. Это как пытаться создать "просто автомобиль" без указания марки и модели. Kotlin требует конкретной реализации.

К счастью, у нас есть несколько элегантных способов обойти это ограничение.

2. Самый простой способ: mutableListOf()

Это король пустых списков. Стандартная функция-фабрика из стандартной библиотеки Kotlin:

val emptyList = mutableListOf<String>()
println(emptyList) // Вывод: []
println(emptyList.size) // Вывод: 0

Почему это круто:

  • Не нужно указывать тип, если он может быть выведен из контекста
  • Создаёт MutableList с типом ArrayList под капотом
  • Читается как "создай мне изменяемый список из ничего"

Добавлять элементы — одно удовольствие:

val numbers = mutableListOf<Int>()
numbers.add(1)
numbers.add(2)
numbers.add(3)
println(numbers) // [1, 2, 3]

Этот метод подходит для 90% случаев. Запомните его как основной.

3. Классический ArrayList() — возвращение короля

Если вы пришли из Java, этот способ покажется вам родным. Kotlin полностью совместим с Java Collections Framework, поэтому вы можете использовать ArrayList напрямую:

val list = ArrayList<String>()
println(list) // []

Но есть нюанс: ArrayList — это конкретная реализация интерфейса MutableList. Если в дальнейшем вы захотите поменять реализацию (например, на LinkedList), придётся менять тип переменной. В этом смысле mutableListOf() гибче, так как возвращает MutableList.

Когда использовать ArrayList():

  • Когда нужна максимальная производительность (ArrayList быстрее LinkedList для доступа по индексу)
  • Когда вы работаете с Java-библиотеками, ожидающими именно ArrayList
  • Когда вы сознательно выбираете конкретную реализацию

4. Хитрый способ: MutableList(size) { defaultValue }

Иногда пустой список — это не совсем "пустой". Бывает, нужно создать список с заранее известным размером, но с пустыми значениями. Для этого есть перегрузка конструктора:

// Создаём список из 5 элементов, каждый — пустая строка
val list = MutableList(5) { "" }
println(list) // [, , , , ]
println(list.size) // 5

Это не совсем пустой список, но список, инициализированный "пустышками". Полезно, когда вы точно знаете количество элементов, но будете их перезаписывать.

Для полного нуля используйте mutableListOf(). А этот способ — для ситуаций "заполню потом".

5. Пустой список через конструктор с коллекцией

Ещё один способ — передать пустую коллекцию в конструктор:

val emptyList = mutableListOf<String>().toMutableList()
// или
val anotherEmpty = ArrayList(emptyList<String>())

Но это уже извращение. Зачем создавать пустой список, чтобы скопировать его в другой пустой список? Разве что для демонстрации возможностей. В реальном коде так делать не стоит.

6. Сравнение способов: что выбрать?

Давайте сведём все варианты в таблицу (мысленно, конечно):

  • mutableListOf() — универсальный выбор, рекомендуется для 90% случаев
  • ArrayList() — когда нужна конкретная реализация или совместимость с Java
  • MutableList(size) {} — когда нужно создать список фиксированного размера с дефолтными значениями
  • Конструктор с коллекцией — только для учебных примеров

Мой личный фаворит — mutableListOf(). Он короткий, понятный и не привязывает к конкретной реализации.

7. Частые ошибки новичков

Давайте разберём грабли, на которые наступают почти все:

Ошибка 1: Использование listOf() вместо mutableListOf()

val list = listOf<String>() // Это неизменяемый список!
list.add("Hello") // Ошибка компиляции!

listOf() создаёт List, а не MutableList. Если вы планируете изменять список — используйте mutableListOf().

Ошибка 2: Забыли указать тип

val list = mutableListOf() // Ошибка: не удаётся вывести тип
list.add(1)
list.add("строка") // Ошибка: тип не соответствует

Kotlin строго типизирован. Если не указать тип, компилятор не сможет понять, какие элементы вы собираетесь хранить. Всегда указывайте тип в угловых скобках или в контексте, где его можно вывести:

val list = mutableListOf<Int>() // Правильно
list.add(1) // Ок

Ошибка 3: Путаница между MutableList и List в сигнатурах функций

fun process(list: MutableList<Int>) { // Требует изменяемый список
    list.add(1)
}

fun main() {
    val immutableList = listOf(1, 2, 3)
    process(immutableList) // Ошибка: типы не совпадают
}

Если ваша функция изменяет список, принимайте

Блоги

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