Sobes.tech
Middle

Jak pracovat s proudy (streams) v Kotlinu?

sobes.tech AI

Odpověď od AI

V Kotlinu se pro práci s datovými proudy (analogicky Java 8 Streams API) používají rozšiřující funkce pro kolekce, které jsou poskytovány knihovnou standardních funkcí. Nejedná se o samostatné API, ale o sadu metod z kotlin.collections.

Hlavní operace s proudy jsou rozděleny na:

  • Meziprodukční (Intermediate) operace: Vrací novou kolekci a jsou "líné" (provádí se pouze při volání terminální operace). Příklady: filter, map, flatMap, distinct, sorted, take, drop.
  • Terminální (Terminal) operace: Ukončují sekvenci operací a vracejí výsledek (nikoliv kolekci). Spouštějí vykonání všech meziprodukčních operací. Příklady: forEach, reduce, fold, count, sum, average, min, max, toList, toSet, toMap.

Existuje také koncept sekvencí (sequences), který zajišťuje explicitní lenivost. Sekvence zpracovávají prvky po jednom podle potřeby, což může být efektivnější pro velké kolekce nebo dlouhé řetězce operací:

  • Vytvoření sekvence: collection.asSequence()
  • Převod zpět na kolekci: sequence.toList()
// Příklad použití standardních funkcí pro zpracování proudů
fun processCollection() {
    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

    val evenSquares = numbers
        .filter { it % 2 == 0 } // Meziprodukční operace: filtrujeme sudá čísla
        .map { it * it }     // Meziprodukční operace: umocňujeme na druh

    println(evenSquares) // Terminální operace: vypisujeme kolekci (provádí filtraci a map)

    val sumOfOdd = numbers
        .filter { it % 2 != 0 } // Meziprodukční
        .sum()                // Terminální (vykonávaná): spočítá součet lichých

    println(sumOfOdd)
}

// Příklad použití sekvencí
fun processSequence() {
    val largeCollection = (1..1_000_000).toList()

    // S kolekcemi (ne líně): filter a map se provedou pro všechny prvky
    val resultCollection = largeCollection
        .filter { it % 2 == 0 }
        .map { it * 2 }
        .take(10) // take(10) se provádí po filtraci a map pro všechny

    println("Result Collection size: ${resultCollection.size}")

    // S sekvencemi (líně): filter, map a take se provádějí po jednom prvku
    val resultSequence = largeCollection.asSequence()
        .filter { it % 2 == 0 } // filter se provádí pro každý prvek
        .map { it * 2 }     // map se provádí pro každý projítý prvek
        .take(10)         // take(10) zastaví zpracování po 10 prvcích

    println("Result Sequence size: ${resultSequence.toList().size}") // toList() spouští sekvenci
}

fun main() {
    processCollection()
    processSequence()
}

Porovnávací tabulka standardních funkcí a sequences z hlediska lenivosti:

Vlastnost Standardní funkce kolekcí Sequences
Línost Nezřejmá lenivost u meziprodukčních operací, ale terminální operace zpracovává celý řetězec najednou Explicitní lenivost: operace se provádějí po jednom prvku podle potřeby
Efektivita Může být méně efektivní pro velké kolekce a dlouhé řetězce operací kvůli meziprodukčním kolekcím Efektivnější pro velké kolekce a dlouhé řetězce operací
Použití Vhodné pro malé a střední kolekce Vhodné pro velké kolekce nebo operace, které lze předčasně ukončit (take, find, first, any, all, none)

Použití standardních funkcí na kolekcích je většinou dostačující a stručnější. Sequences jsou doporučovány, když je potřeba explicitní lenivost pro optimalizaci výkonu při práci s velkými objemy dat.