Зачем нужен Sequence в Kotlin и как он работает с памятью
Что проверяют
Понимаете ли вы разницу между жадной и ленивой обработкой коллекций и знаете ли, когда ленивость не окупается.
Как отвечать
Обычные операции над коллекцией жадные: каждый вызов map или filter создаёт новый список целиком. Цепочка из трёх операций над списком в миллион элементов создаст три промежуточных списка.
Sequence обрабатывает элементы лениво и по одному: элемент проходит всю цепочку до конца, потом берётся следующий. Промежуточных коллекций нет, память тратится на один элемент, а работа начинается только при завершающей операции (toList, first, sum, count).
val result = jobs.asSequence()
.filter { it.isActive }
.map { it.title }
.take(10) // после десятого элемента обработка прекратится
.toList()Когда это выгодно: большая коллекция, длинная цепочка операций, ранний выход (first, take, any), бесконечная последовательность (generateSequence), чтение файла построчно.
Когда не выгодно и это стоит сказать самому: маленькие коллекции. У последовательности есть накладные расходы на вызовы через итератор, и на списке из десятка элементов обычная цепочка окажется быстрее. Ещё нюанс: последовательность проходится один раз, повторное использование потребует нового объекта, а операции, требующие всех элементов сразу (sorted), внутри всё равно материализуют коллекцию.
Где спотыкаются
Ставят asSequence везде подряд и получают код медленнее исходного.
Ожидают выполнения без завершающей операции: цепочка просто ничего не сделает.
Забывают, что sorted в середине цепочки обнуляет выигрыш по памяти.