Avatar ·

Как инициализировать список (List<T>) в Kotlin? Разбираем все способы

Всем привет! Я только начал изучать Kotlin после Java, и столкнулся с проблемой: как правильно создать и инициализировать список? В Java я привык делать так: ```java List list = new ArrayList<>(); list.add("a"); list.add("b"); ``` Но в Kotlin я вижу, что есть какие-то `listOf(...)`, `mutableListOf(...)`, а ещё можно использовать конструкторы. Я попробовал написать: ```kotlin val list: List = listOf("a", "b") // это работает list.add("c") // ошибка компиляции! ``` Почему я не могу добавить элемент? И как тогда сделать изменяемый список? Ещё я слышал про `ArrayList()`, но не понимаю, как его правильно использовать в Kotlin. Подскажите, пожалуйста, все возможные способы инициализации списков, чтобы я больше не путался. Мне нужно как для неизменяемых (read-only) списков, так и для изменяемых (mutable). Заранее спасибо! <<>>

Основные способы инициализации списков в Kotlin

В Kotlin есть чёткое разделение на неизменяемые (read-only) и изменяемые (mutable) списки. Это сделано для безопасности — по умолчанию список не предполагает изменения, что предотвращает случайные ошибки.

1. Неизменяемые списки (List)

Используйте функцию listOf(). Такой список нельзя изменить после создания: нет методов add, remove и т.д.

val numbers: List<Int> = listOf(1, 2, 3, 4, 5)
val emptyList: List<String> = listOf() // пустой список
val singleList: List<String> = listOf("Kotlin") // список из одного элемента

Обратите внимание: тип List<T> — это интерфейс, а listOf() возвращает оптимизированную реализацию (обычно java.util.Arrays.ArrayList или java.util.Collections.emptyList()).

2. Изменяемые списки (MutableList)

Для списков, которые вы планируете изменять, используйте mutableListOf():

val mutableNumbers = mutableListOf(1, 2, 3)
mutableNumbers.add(4)      // [1, 2, 3, 4]
mutableNumbers.remove(2)   // [1, 3, 4]
mutableNumbers[0] = 10     // [10, 3, 4]

// Пустой изменяемый список
val emptyMutable = mutableListOf<String>()

По умолчанию mutableListOf() создаёт ArrayList. Вы также можете явно указать реализацию:

val arrayList = ArrayList<String>() // эквивалентно mutableListOf()
val linkedList = LinkedList<String>()

3. Инициализация с помощью конструкторов

Вы можете использовать конкретные классы коллекций Java, но Kotlin рекомендует свои функции-фабрики. Однако если вам нужен список фиксированного размера с одним значением:

// Список из 10 нулей
val zeros = MutableList(10) { 0 }   // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

// Список с индексами в качестве значений
val indices = MutableList(5) { index -> index * index } // [0, 1, 4, 9, 16]

Конструктор MutableList(size, init) — очень мощный инструмент, позволяющий заполнить список любыми значениями через лямбду.

4. Преобразование из других коллекций

Часто список получается из другого источника (например, из массива или Set):

val array = intArrayOf(1, 2, 3)
val listFromArray: List<Int> = array.toList()

val set = setOf("a", "b")
val mutableFromSet: MutableList<String> = set.toMutableList()

5. Инициализация с помощью билдера (для сложной логики)

Если нужно добавить элементы по условию, используйте buildList (доступен с Kotlin 1.3):

val complexList = buildList {
    add("start")
    if (someCondition) {
        add("condition met")
    }
    addAll(listOf("end1", "end2"))
}
// Результат: неизменяемый список

Важные моменты

  • Не путайте List и MutableList. Если вы объявили val list: List<Int> = ..., то не сможете изменить его, даже если внутри он mutable. Это защита на уровне интерфейса.
  • Используйте listOf() по умолчанию. Если не планируете изменять список, всегда выбирайте неизменяемую версию — это делает код безопаснее и читаемее.
  • Производительность. listOf() для малых списков (до 2 элементов) может возвращать специальные оптимизированные классы. Для больших — ArrayList.

Пример для новичка

fun main() {
    // Неизменяемый список дней недели
    val daysOfWeek = listOf("Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс")
    
    // Изменяемый список для задач
    val tasks = mutableListOf("Купить продукты", "Помыть посуду")
    tasks.add("Покормить кота")
    tasks.removeAt(0)
    
    println(daysOfWeek)
    println(tasks)
}

Теперь вы знаете все основные способы. Начните с listOf и mutableListOf, а когда освоитесь — используйте MutableList(size) { ... } для эффективного заполнения.

<<>>

Альтернативный подход: использование Java-совместимости

Если вы пришли из Java и хотите использовать привычный синтаксис, Kotlin позволяет напрямую работать с Java-коллекциями:

import java.util.ArrayList

val list = ArrayList<String>()
list.add("Hello")
list.add("World")

Но помните: ArrayList в Kotlin — это тот же java.util.ArrayList, и он всегда изменяемый. Однако такой код менее "идиоматичен" для Kotlin. Лучше использовать mutableListOf() — он короче и понятнее.

Ещё один способ: инициализация через spread-оператор

Если у вас есть массив, вы можете "развернуть" его в список:

val array = arrayOf("A", "B", "C")
val list = listOf(*array) // spread-оператор *
println(list) // [A, B, C]

Это удобно, когда нужно быстро преобразовать массив в неизменяемый список без вызова toList().

Для пуристов: использование конструктора с vararg

val list = listOf("one", "two", "three") // vararg в действии

Функция listOf принимает vararg elements: T, поэтому вы можете передавать любое количество элементов. Это самый простой и читаемый способ для небольших списков.

В итоге: для 90% случаев вам хватит listOf() и mutableListOf(). Остальные способы — для специфических ситуаций.