Ako pracovať s tokmi (streams) v Kotlin?
sobes.tech AI
Odpoveď od AI
V Kotlinu sa spracovaním tokov dát (analóg Java 8 Streams API) sa používajú rozšírené funkcie pre kolekcie, ktoré poskytuje štandardná knižnica funkcií. Nie je to samostatné API, ale súbor metód z kotlin.collections.
Hlavné operácie s tokmi sú rozdelené na:
- Medziprodukčné (Intermediate) operácie: Vrátia novú kolekciu a sú "lenivé" (vykonávajú sa iba pri volaní terminálnej operácie). Príklady:
filter,map,flatMap,distinct,sorted,take,drop. - Terminálne (Terminal) operácie: Ukončia sekvenciu operácií a vrátia výsledok (nie kolekciu). Spúšťajú vykonanie všetkých medziprodukčných operácií. Príklady:
forEach,reduce,fold,count,sum,average,min,max,toList,toSet,toMap.
Existuje aj koncept sekvencií (sequences), ktorý zabezpečuje explicitnú lenivosť. Sekvencie spracovávajú prvky jeden po druhom podľa potreby, čo môže byť efektívnejšie pre veľké kolekcie alebo dlhé reťazce operácií:
- Vytvorenie sekvencie:
collection.asSequence() - Prevod späť na kolekciu:
sequence.toList()
// Príklad použitia štandardných funkcií na spracovanie tokov
fun processCollection() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val evenSquares = numbers
.filter { it % 2 == 0 } // Medziprodukčná operácia: filtrujeme párne čísla
.map { it * it } // Medziprodukčná operácia: umocňujeme na druh
println(evenSquares) // Terminálna operácia: vypisuje kolekciu (vykonáva filtráciu a map)
val sumOfOdd = numbers
.filter { it % 2 != 0 } // Medziprodukčná
.sum() // Terminálna (vykonávaná): počíta súčet nepárnych
println(sumOfOdd)
}
// Príklad použitia sekvencií
fun processSequence() {
val largeCollection = (1..1_000_000).toList()
// S kolekciami (ne lenivými): filter a map sa vykonajú pre všetky prvky
val resultCollection = largeCollection
.filter { it % 2 == 0 }
.map { it * 2 }
.take(10) // take(10) sa vykoná po filtrovaní a map pre všetky
println("Result Collection size: ${resultCollection.size}")
// So sekvenciami (lenivými): filter, map a take sa vykonávajú po jednom prvku
val resultSequence = largeCollection.asSequence()
.filter { it % 2 == 0 } // filter sa vykonáva pre každý prvok
.map { it * 2 } // map sa vykonáva pre každý prešlý filter prvok
.take(10) // take(10) zastaví spracovanie po 10 prvkoch
println("Result Sequence size: ${resultSequence.toList().size}") // toList() spúšťa vykonanie sekvencie
}
fun main() {
processCollection()
processSequence()
}
Porovnávacia tabuľka štandardných funkcií a sequences z hľadiska lenivosti:
| Vlastnosť | Štandardné funkcie kolekcií | Sequences |
|---|---|---|
| Lenivosť | Nezrejmá lenivosť pre medziprodukčné operácie, ale terminálna operácia spracováva celý reťazec naraz | Jasná lenivosť: operácie sa vykonávajú po prvku podľa potreby |
| Efektívnosť | Môže byť menej efektívna pre veľké kolekcie a dlhé reťazce operácií kvôli medziprodukčným kolekciám | Efektívnejšia pre veľké kolekcie a dlhé reťazce operácií |
| Použitie | Vhodná pre malé a stredné kolekcie | Vhodná pre veľké kolekcie alebo operácie, ktoré môžu byť skrátené skôr (take, find, first, any, all, none) |
Použitie štandardných funkcií na kolekciách je väčšinou dostatočné a stručnejšie. Sequences sa odporúčajú, keď je potrebná jasná lenivosť na optimalizáciu výkonu pri práci s veľkými objemami dát.