В чем разница между ArrayList<String>() и mutableListOf<String>() в Kotlin?
Основное различие: тип vs реализация
Главное отличие лежит в плоскости типизации и абстракции. Давайте разберем оба подхода по порядку.
ArrayList<String>()
Здесь вы напрямую создаете экземпляр конкретного класса ArrayList, который является частью Java Collections Framework. Переменная объявлена с типом ArrayList<String>. Это означает:
- Вы жестко привязываетесь к конкретной реализации списка.
- Код будет использовать именно
ArrayListс его внутренней структурой на основе массива. - Если в будущем вы захотите сменить реализацию (например, на
LinkedList), придется менять объявление переменной.
// Жесткая привязка к ArrayList
val list: ArrayList<String> = ArrayList()
list.add("Java")
// list теперь может быть только ArrayList
mutableListOf<String>()
Это фабричная функция из стандартной библиотеки Kotlin. Она возвращает MutableList<T> — интерфейс, а не конкретный класс. Важные моменты:
- Тип переменной —
MutableList<String>(интерфейс), а не конкретная реализация. - Внутри
mutableListOf()по умолчанию создаетсяArrayList, но это деталь реализации. - Вы не зависите от конкретной реализации — это программирование на уровне интерфейсов.
// Программирование через интерфейс
val list: MutableList<String> = mutableListOf()
list.add("Kotlin")
// Реализация может быть любой, соответствующей интерфейсу
Что же происходит под капотом?
Если заглянуть в исходники Kotlin, то mutableListOf() — это inline-функция, которая вызывает конструктор ArrayList. Но! Она возвращает результат, приведенный к типу MutableList. То есть:
public inline fun <T> mutableListOf(): MutableList<T> = ArrayList()
Оба варианта в рантайме создают один и тот же объект — java.util.ArrayList. Разница исключительно в типе переменной.
Практические рекомендации
В 95% случаев используйте mutableListOf(). Почему?
- Гибкость. Вы можете легко заменить реализацию, не меняя код. Например, если понадобится потокобезопасный список или список на основе связного списка — достаточно изменить фабричный метод.
- Единообразие. В Kotlin принято работать через интерфейсы. Для неизменяемых списков используйте
listOf(), для изменяемых —mutableListOf(). - Читаемость. Другие разработчики сразу поймут, что список изменяемый, и не будут путаться с Java-стилем.
// Хороший стиль Kotlin
val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
numbers.add(4)
// Плохой стиль (Java-наследие)
val numbers2: ArrayList<Int> = ArrayList()
numbers2.add(4)
Когда все же использовать ArrayList?
Есть редкие случаи, когда это оправдано:
- Вы работаете с Java-библиотекой, которая требует именно
ArrayList. - Вам нужны специфические методы
ArrayList, которых нет в интерфейсе (например,trimToSize()илиensureCapacity()). - Вы пишете критичный к производительности код и хотите явно указать реализацию для избежания лишних виртуальных вызовов (хотя современные JIT-компиляторы это оптимизируют).
Итог
ArrayList<String>() — это конкретный класс. mutableListOf<String>() — это фабричный метод, возвращающий интерфейс. По умолчанию оба создают ArrayList, но второй вариант предпочтительнее, так как следует принципам ООП и Kotlin-стилю.
Дополнение: производительность и скрытые возможности
Коллега верно описал основное различие. Я добавлю несколько технических нюансов, которые стоит знать.
Производительность
Многие думают, что mutableListOf() медленнее из-за вызова фабричной функции, но это не так. Благодаря inline-механизму Kotlin, код mutableListOf() встраивается прямо в место вызова, и никакого оверхеда нет. Оба варианта компилируются в одинаковый байт-код.
// Код на Kotlin
val a = mutableListOf<String>()
val b = ArrayList<String>()
// Оба превращаются в:
// new ArrayList()
Что еще возвращает mutableListOf?
Хотя по умолчанию это ArrayList, в некоторых средах (например, Kotlin/Native или Kotlin/JS) реализация может отличаться. mutableListOf() гарантирует только соблюдение контракта MutableList, но не конкретную реализацию. Это особенно важно для мультиплатформенных проектов.
Практический совет
Если вам нужно создать список с начальными элементами, mutableListOf удобнее:
// mutableListOf с элементами
val list = mutableListOf("A", "B", "C")
// ArrayList так не умеет, нужно писать длиннее
val list2 = ArrayList<String>(listOf("A", "B", "C"))
В целом, придерживайтесь правила: в Kotlin используйте Kotlin-стиль. mutableListOf() — это идиоматично, читаемо и гибко. ArrayList() оставьте для обратной совместимости с Java-кодом.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги