Последовательности и коллекции
Когда каждая из них эффективнее
«Последовательности и коллекции» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.
Последовательности и коллекции
И последовательности, и коллекции предлагают одинаковые функциональные операции, но вычисляют их по-разному. Понимание того, когда использовать каждый вариант, помогает писать эффективный и понятный код.
Итоги по немедленным коллекциям
Коллекции работают немедленно: каждая операция сразу обрабатывает все элементы и создаёт новую коллекцию. Это просто и быстро для небольших объёмов данных.
fun main() {
val result = listOf(1, 2, 3).map { it + 1 }.filter { it > 2 }
println(result)
}Итоги по ленивым последовательностям
Последовательности работают лениво: операции строят конвейер, который обрабатывает элементы по одному только при обработке последовательности, не создавая промежуточные коллекции.
fun main() {
val result = listOf(1, 2, 3).asSequence().map { it + 1 }.filter { it > 2 }.toList()
println(result)
}Когда выигрывают коллекции
Для небольших коллекций и коротких цепочек коллекции обычно быстрее и понятнее. Последовательности создают дополнительные затраты на каждый элемент из-за вызовов итератора, и для крошечных объёмов данных эти затраты могут превысить преимущества.
Когда выигрывают последовательности
Последовательности выигрывают при больших объёмах данных, длинных цепочках операций или когда нужна только часть результата: первое совпадение или первые N элементов. Они не создают большие промежуточные списки и останавливаются раньше.
fun main() {
val firstEvenSquare = (1..1000000).asSequence()
.map { it * it }
.first { it % 2 == 0 }
println(firstEvenSquare)
}Измеряем разницу
В этом примере с большим диапазоном последовательность не создаёт промежуточный список из миллиона элементов, который создала бы немедленная версия.
fun main() {
val seqResult = (1..1000).asSequence()
.filter { it % 2 == 0 }
.map { it * 3 }
.take(3)
.toList()
println(seqResult)
}Затраты памяти
Немедленные цепочки одновременно хранят в памяти каждый промежуточный список. Последовательности пропускают через конвейер только текущий элемент, поэтому пиковое потребление памяти остаётся небольшим даже в длинных конвейерах.
Преимущество досрочного завершения
Если завершающая операция может закончить работу раньше, например first, find или any, последовательности пропускают оставшиеся элементы, тогда как немедленные коллекции уже обработали бы всё.
fun main() {
val found = (1..100).asSequence()
.map { println("checking $it"); it }
.any { it == 3 }
println("Found: $found")
}Остерегайтесь операций с состоянием
Операциям вроде sorted, distinct и groupBy нужны все элементы, поэтому они уменьшают пользу ленивого выполнения. Конвейер, в котором преобладают такие операции, может не получить преимуществ от последовательности.
Практическая рекомендация
Практическое правило: для ясности по умолчанию выбирайте коллекции. Переходите к последовательности, когда обрабатываете большие объёмы данных, объединяете много операций в цепочку или нужна лишь небольшая часть результата. Если производительность критична, всегда проводите измерения.
Один интерфейс, разные механизмы
Поскольку названия операций совпадают, обычно можно перейти с одного варианта на другой, добавив или удалив asSequence() и завершающий вызов toList(). Поэтому эксперименты с производительностью остаются малорискованными.
fun main() {
val data = listOf(1, 2, 3, 4, 5)
val asList = data.map { it * 2 }.filter { it > 4 }
val asSeq = data.asSequence().map { it * 2 }.filter { it > 4 }.toList()
println(asList == asSeq)
}Быстрая проверка
В какой ситуации последовательность, скорее всего, превзойдёт коллекцию по производительности?
Итоги
Коллекции работают немедленно и лучше подходят для небольших объёмов данных и ясного кода; последовательности работают лениво и лучше подходят для больших объёмов данных, длинных цепочек или частичных результатов благодаря отсутствию промежуточных списков и досрочному завершению. Помните об операциях с состоянием. У них одинаковый интерфейс, поэтому переход между ними прост. На этом курс по последовательностям завершён.
Часто задаваемые вопросы
Урок «Последовательности и коллекции» бесплатный?
Да — полный текст урока «Последовательности и коллекции» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.
Чему я научусь в уроке «Последовательности и коллекции»?
Когда каждая из них эффективнее Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Kotlin Academy?
Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Последовательности и коллекции»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Kotlin Academy?
Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Зачем нужны последовательности
- Создание последовательностей
- Отложенные операции
- Последовательности и коллекции