Комментарии 19
Да, джаве прямо сильно не хватает extention-методов, можно было бы много острых углов стандартной библиотеки срезать.
Ммм, ну, типа, с подключением!
Данный класс неизменяемый— здесь вы могли использовать Records.
В таких уроках надо упомянуть важный момент: методы наподобие map
и filter
на коллекциях создают новую коллекцию, то есть могут вести к серьёзному выделению памяти, даже если в конце вычислений используется один или всего несколько элементов. Для предотвращения этого надо брать последовательности (sequence) от коллекций: list.asSequence().map { ... }.filter { ...}
, тогда вычисления могут быть ленивыми и без выделения памяти. Это аналог Stream
в чистой Java.
Более того, если вам не нужны распараллеливаемые streams из Java, можно рекомендовать использовать только последовательности Kotlin — оверхед при выполнении может быть гораздо меньше. А ещё свои операторы для sequences написать гораздо легче, чем для streams.
Зато ленивые вычисления гораздо медленнее, поэтому говорить «надо брать последовательности (sequence) от коллекций» — некорректно. Надо определиться, что для данной задачи важнее: производительность, или минимизация накладных расходов, и выбирать жадный или ленивый вариант работы с коллекциями соответственно.
@Test
fun testFib()
{
val fibonacciSequence = sequence {
var a = 0
var b = 1
while (true)
{
yield(a)
val f = a + b
a = b
b = f
}
}
val res = measureTimeMillis {
fibonacciSequence
.take(10)
.groupBy { it % 2 == 0 }
.forEach(::println)
}
}
@Test
fun testFib1()
{
val fibonacciStream = Stream.iterate(Pair(1, 0)) { (a, b) ->
Pair(b, a + b)
}
val res = measureTimeMillis {
fibonacciStream
.limit(10)
.map { it.second }
.collect(Collectors.groupingBy { it % 2 == 0 })
.forEach(::println)
}
}
Или я что-то упустил?
Во-первых, так вы ничего не намеряете. Просто миллисекунды считать — это крайне грубо. Надо обязательно брать JMH.
Во-вторых, эта функция sequence
работает через корутины. Да, там накладные расходы могуть быть побольше.
Более точным аналогом будет:
generateSequence(1 to 0) { (a, b) -> b to a + b }
.take(10)
.map { it.second }
.groupBy { it % 2 == 0 }
.forEach(::println)
Здесь всё на обычных лямбдах и итераторах.
у меня еще вопрос — если я делаю что-то типа myList.asSequence().flatMap{} и myList.stream().flatMap{}, последнее быстрее
Не подскажете, почему?
testStreams
Переезд из Java в Kotlin: как забрать коллекции с собой