Ответ 1
Основное различие заключается в семантике и реализации функций расширения stdlib для Iterable<T>
и Sequence<T>
.
-
Для
Sequence<T>
функции расширения выполняются, где это возможно, лениво, подобно промежуточным операциям Java Streams. Например,Sequence<T>.map {... }
возвращает другуюSequence<R>
и фактически не обрабатывает элементы, пока не будетtoList
терминальная операция, такая какtoList
илиfold
.Рассмотрим этот код:
val seq = sequenceOf(1, 2) val seqMapped: Sequence<Int> = seq.map { print("$it "); it * it } // intermediate print("before sum ") val sum = seqMapped.sum() // terminal
Это печатает:
before sum 1 2
Sequence<T>
предназначен для ленивого использования и эффективной конвейеризации, когда вы хотите максимально сократить работу, выполняемую в терминальных операциях, так же, как в Java Streams. Однако лень вносит некоторые накладные расходы, что нежелательно для обычных простых преобразований небольших коллекций и делает их менее производительными.В общем, нет хорошего способа определить, когда это необходимо, поэтому в Kotlin лень stdlib делается явным и извлекается в интерфейс
Sequence<T>
чтобы по умолчанию не использовать его во всехIterable
. -
Для
Iterable<T>
, напротив, функции расширения с семантикой промежуточных операций работают с большим удовольствием, сразу же обрабатывают элементы и возвращают другойIterable
. Например,Iterable<T>.map {... }
возвращаетList<R>
с результатами сопоставления в нем.Эквивалентный код для Iterable:
val lst = listOf(1, 2) val lstMapped: List<Int> = lst.map { print("$it "); it * it } print("before sum ") val sum = lstMapped.sum()
Это распечатывает:
1 2 before sum
Как сказано выше,
Iterable<T>
по умолчанию не ленив, и это решение хорошо себя зарекомендовало: в большинстве случаев он имеет хорошую локальность ссылок, таким образом, используя преимущества кэша ЦП, прогнозирования, предварительной выборки и т.д., Так что даже многократное копирование коллекция все еще работает достаточно хорошо и работает лучше в простых случаях с небольшими коллекциями.Если вам нужно больше контроля над конвейером оценки, существует явное преобразование в ленивую последовательность с функцией
Iterable<T>.asSequence()
.