Какой оператор требует доступа ко всем элементам Sequence в Kotlin
Что проверяют
Понимаете ли вы, как устроена ленивость Sequence и где она заканчивается. Ожидаемый ответ: sorted() и его варианты. Следом спрашивают, что будет с бесконечной последовательностью и когда Sequence вообще выгоднее обычного List.
Как отвечать
Sequence обрабатывает элементы по одному через всю цепочку: первый элемент проходит map и filter, потом второй, и промежуточных списков не создаётся. Документация Kotlin делит операции по двум признакам:
- промежуточные и терминальные:
map,filter,takeвозвращают новуюSequenceи ничего не вычисляют, пока не вызван терминальный оператор вродеtoList(),first(),sum(); - stateless и stateful: большинству промежуточных операций хватает текущего элемента или небольшого счётчика, а stateful хранят состояние, растущее с числом элементов.
Ответ на сам вопрос: промежуточная операция sorted(), а также sortedBy, sortedDescending, sortedWith. Отсортировать, не увидев всех элементов, невозможно, поэтому при запросе первого элемента она вычитывает всю последовательность в буфер, сортирует и только потом отдаёт результат. При этом память уходит на все элементы сразу.
Хорошо добавить различие с distinct(): она тоже хранит состояние, но отдаёт элементы по мере прохода, запоминая только уже встреченные. Из терминальных все элементы нужны toList(), count(), sum(), last(), maxOrNull(), а first(), any(), find() останавливаются на первом подходящем.
Практический вывод для Android: на бесконечной generateSequence вызов sorted() не завершится никогда, а на большом объёме съест память и приведёт к OutOfMemoryError. Наконец, для небольших коллекций Sequence не обязательно быстрее List, накладные расходы на итераторы могут перевесить экономию на промежуточных списках.
Где спотыкаются
Отвечают только «toList()». Это терминальная операция, ей по определению нужны все элементы, а интервьюер ждёт промежуточную операцию, которая ломает ленивость.
Путают sorted() с distinct() и filter(), считая их одинаково «жадными».
Считают, что Sequence всегда быстрее. На коротком списке из пары операций разницы нет или она в пользу List.