Sobes.tech
Middle

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.