Kaip dirbti su srautais (streams) Kotlin?
sobes.tech AI
Atsakymas iš AI
Kotlin'e duomenų srautų (Java 8 Streams API analogas) darbui naudojamos kolekcijų plėtros funkcijos, teikiamos standartinių funkcijų bibliotekoje. Tai nėra atskiras API, o metodų rinkinys kotlin.collections:
Pagrindinės srautų operacijos skirstomos į:
- Tarpines (Intermediate operations): Grąžina naują kolekciją ir yra "lėtos" (vykdomos tik iškvietus galutinę operaciją). Pavyzdžiai:
filter,map,flatMap,distinct,sorted,take,drop. - Galutinės (Terminal operations): Užbaigia operacijų seką ir grąžina rezultatą (ne kolekciją). Vykdo visas tarpines operacijas. Pavyzdžiai:
forEach,reduce,fold,count,sum,average,min,max,toList,toSet,toMap.
Taip pat egzistuoja sekų (sequences) koncepcija, kuri užtikrina aiškią "lėto" vykdymą. Sekos apdoroja elementus po vieną pagal poreikį, kas gali būti efektyviau didelėms kolekcijoms ar ilgiems operacijų grandinėms:
- Sekos sukūrimas:
collection.asSequence() - Konvertavimas atgal į kolekciją:
sequence.toList()
// Standartinių funkcijų naudojimo pavyzdys srautų apdorojimui
fun processCollection() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val evenSquares = numbers
.filter { it % 2 == 0 } // Tarpinė operacija: filtruoja lyginius skaičius
.map { it * it } // Tarpinė operacija: kvadratai
println(evenSquares) // Galutinė operacija: išveda kolekciją (įvykdo filtravimą ir map)
val sumOfOdd = numbers
.filter { it % 2 != 0 } // Tarpinė
.sum() // Galutinė (susumuoja nelyginius)
println(sumOfOdd)
}
// Sekų naudojimo pavyzdys
fun processSequence() {
val largeCollection = (1..1_000_000).toList()
// Su kolekcijomis (ne lėtai): filter ir map vykdomi visiems elementams iš karto
val resultCollection = largeCollection
.filter { it % 2 == 0 }
.map { it * 2 }
.take(10) // take(10) vykdomas po filtravimo ir map visiems
println("Result Collection size: ${resultCollection.size}")
// Su sekomis (lėtai): filter, map ir take vykdomi po vieną elementą
val resultSequence = largeCollection.asSequence()
.filter { it % 2 == 0 } // filter vykdomas kiekvienam elementui paeiliui
.map { it * 2 } // map vykdomas kiekvienam praleistam elementui
.take(10) // take(10) sustabdo apdorojimą po 10 elementų
println("Result Sequence size: ${resultSequence.toList().size}") // toList() iškviečia sekos vykdymą
}
fun main() {
processCollection()
processSequence()
}
Lyginamoji lentelė apie standartinių funkcijų ir sekų (sequences) savybes:
| Savybė | Standartinės kolekcijų funkcijos | Sequences |
|---|---|---|
| Lėtumas | Numatytas lėtumas tarpinių operacijų, bet galutinė operacija apdoroja visą grandinę | Aiškus lėtumas: operacijos vykdomos po vieną elementą pagal poreikį |
| Efektyvumas | Gali būti mažiau efektyvus didelėms kolekcijoms ir ilgiems operacijų grandinėms dėl tarpinių kolekcijų | Daug efektyviau didelėms kolekcijoms ir ilgiems operacijų grandinėms |
| Naudojimas | Tinka mažoms ir vidutinėms kolekcijoms | Tinka didelėms kolekcijoms arba operacijoms, kurios gali būti anksti nutrauktos (take, find, first, any, all, none) |
Naudojant standartines funkcijas kolekcijose dažniausiai pakanka ir yra trumpiau. Sequences rekomenduojamos, kai reikalingas aiškus lėtumas optimizacijai dirbant su dideliais duomenų kiekiais.