Как инициализировать пустой MutableList в Kotlin?
Всем привет! Я только начал изучать Kotlin после Java и столкнулся с простой, но запутанной проблемой.
Мне нужно создать пустой изменяемый список (MutableList), чтобы потом добавлять в него элементы. В Java я бы написал что-то вроде ArrayList. Но в Kotlin я вижу много разных способов и не понимаю, какой из них правильный.
Вот что я пробовал:
// Вариант 1
var list1 = mutableListOf()
// Вариант 2
var list2: MutableList<String> = mutableListOf()
// Вариант 3
var list3 = emptyList<String>()
// Вариант 4
var list4 = ArrayList<String>()
Проблема в том, что:
emptyList()возвращает неизменяемый список, и я не могу добавить в него элементы.mutableListOf()без указания типа работает, но потом я не могу добавить строки — пишет ошибку.- Вариант с
ArrayListработает, но выглядит не по-котлиновски.
Подскажите, как правильно создать пустой MutableList, чтобы потом можно было добавлять в него элементы? И какой способ считается идиоматическим в Kotlin?
<<Идиоматический способ: mutableListOf с указанием типа
Самый правильный и краткий способ создать пустой MutableList в Kotlin — использовать функцию mutableListOf() с явным указанием типа элементов:
val list = mutableListOf<String>() // Создаёт пустой MutableList<String>
list.add("Kotlin")
list.add("Java")
println(list) // [Kotlin, Java]
Если вы опустите тип, Kotlin не сможет его вывести из контекста, и вы получите MutableList<Nothing>, в который нельзя ничего добавить, кроме null:
val badList = mutableListOf() // MutableList<Nothing>
// badList.add("Hello") // Ошибка компиляции!
badList.add(null) // Работает, но бесполезно
Поэтому всегда указывайте тип — либо в угловых скобках, либо в объявлении переменной:
// Вариант 1: явный тип в вызове
val list1: MutableList<String> = mutableListOf()
// Вариант 2: тип в угловых скобках (предпочтительно)
val list2 = mutableListOf<String>()
Почему не стоит использовать другие способы?
-
emptyList()— возвращает неизменяемыйList. Вы не сможете вызватьadd(),remove()и т.д. Он полезен, когда нужен только для чтения.val readOnly = emptyList<String>() // readOnly.add("test") // Ошибка компиляции -
ArrayList<String>()— работает, но это прямой вызов Java-класса. Kotlin рекомендует использовать свои фабричные функции для единообразия. Разницы в производительности нет, но код выглядит менее идиоматично. -
listOf()— возвращает неизменяемый список. Даже если вы присвоите его переменной типаMutableList, это приведёт к ошибке компиляции или потребует приведения типов (что небезопасно).
Дополнительные возможности
Если вы хотите сразу создать список с элементами, используйте mutableListOf("a", "b", "c").
Для создания списка определённого размера с заполнением:
val list = MutableList(5) { index -> "Item $index" }
println(list) // [Item 0, Item 1, Item 2, Item 3, Item 4]
Или пустой список с заданной ёмкостью (если знаете, сколько будет элементов):
val list = ArrayList<String>(100) // Ёмкость 100, но список пуст
Однако для повседневного использования mutableListOf<T>() — это стандарт.
Итог
Запомните простое правило:
- Нужен изменяемый список →
mutableListOf<Тип>() - Нужен неизменяемый список →
listOf<Тип>()илиemptyList()
И всегда указывайте тип, чтобы избежать неожиданностей.
<<Альтернативный подход: использование конструктора MutableList
В Kotlin есть ещё один способ создать пустой изменяемый список — через конструктор MutableList с указанием размера и лямбды-инициализатора:
val list = MutableList(0) { "" } // Пустой список строк
Здесь первый аргумент — размер (0), второй — фабричная функция. Это работает, но выглядит избыточно для пустого списка.
Также можно использовать Java-стиль, если вы работаете с существующим Java-кодом:
val list = java.util.ArrayList<String>() // Полный путь к классу
Но это не рекомендуется в чистом Kotlin-проекте.
Когда mutableListOf может не подойти?
Если вам нужно создать список с определённой начальной ёмкостью (например, вы знаете, что будет 1000 элементов), то mutableListOf создаёт список с ёмкостью по умолчанию (10). В таком случае лучше использовать:
val list = ArrayList<String>(1000) // Избегает многократного расширения
Однако для 99% задач mutableListOf<T>() — это лучший выбор.