Sobes.tech
Middle

Wie arbeitet man mit Streams in Kotlin?

sobes.tech KI

Antwort von AI

In Kotlin werden für die Arbeit mit Datenströmen (ähnlich Java 8 Streams API) Erweiterungsfunktionen für Sammlungen verwendet, die von der Standardfunktionsbibliothek bereitgestellt werden. Es ist keine separate API, sondern eine Sammlung von Methoden in kotlin.collections.

Die wichtigsten Operationen mit Strömen sind:

  • Zwischenoperationen: Sie geben eine neue Sammlung zurück und sind "faul" (werden nur bei Aufruf einer terminalen Operation ausgeführt). Beispiele: filter, map, flatMap, distinct, sorted, take, drop.
  • Terminaloperationen: Beenden die Operationenfolge und geben ein Ergebnis zurück (keine Sammlung). Sie lösen die Ausführung aller Zwischenoperationen aus. Beispiele: forEach, reduce, fold, count, sum, average, min, max, toList, toSet, toMap.

Es gibt auch das Konzept der Sequenzen (sequences), das eine explizite Faulheit bietet. Sequenzen verarbeiten Elemente einzeln nach Bedarf, was bei großen Sammlungen oder langen Operationenketten effizienter sein kann:

  • Erstellung einer Sequenz: collection.asSequence()
  • Rückumwandlung in eine Sammlung: sequence.toList()
// Beispiel für die Verwendung von Standardfunktionen für die Flussverarbeitung
fun processCollection() {
    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

    val evenSquares = numbers
        .filter { it % 2 == 0 } // Zwischenoperation: filtert gerade Zahlen
        .map { it * it }     // Zwischenoperation: quadriert

    println(evenSquares) // Terminaloperation: gibt die Sammlung aus (führt filter und map aus)

    val sumOfOdd = numbers
        .filter { it % 2 != 0 } // Zwischen
        .sum()                // Terminal (berechnet die Summe der ungeraden)

    println(sumOfOdd)
}

// Beispiel für die Verwendung von Sequenzen
fun processSequence() {
    val largeCollection = (1..1_000_000).toList()

    // Mit Sammlungen (nicht faul): filter und map werden sofort für alle Elemente ausgeführt
    val resultCollection = largeCollection
        .filter { it % 2 == 0 }
        .map { it * 2 }
        .take(10) // take(10) wird nach filter und map für alle ausgeführt

    println("Ergebnis Sammlung Größe: ${resultCollection.size}")

    // Mit Sequenzen (faul): filter, map und take werden elementweise ausgeführt
    val resultSequence = largeCollection.asSequence()
        .filter { it % 2 == 0 } // filter wird für jedes Element in Reihenfolge ausgeführt
        .map { it * 2 }     // map wird für jedes Element ausgeführt, das den Filter passiert
        .take(10)         // take(10) stoppt die Verarbeitung nach 10 Elementen

    println("Ergebnis Sequenz Größe: ${resultSequence.toList().size}") // toList() löst die Ausführung der Sequenz aus
}

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

Vergleichstabelle der Standardfunktionen und Sequenzen hinsichtlich Faulheit:

Eigenschaft Standardfunktionen der Sammlungen Sequenzen
Faulheit Implizite Faulheit bei Zwischenoperationen, aber die Terminaloperation verarbeitet die gesamte Zwischenkette Explizite Faulheit: Operationen werden elementweise nach Bedarf ausgeführt
Effizienz Kann bei großen Sammlungen und langen Operationenketten aufgrund von Zwischenkollektionen weniger effizient sein Effizienter bei großen Sammlungen und langen Operationenketten
Anwendung Geeignet für kleine und mittlere Sammlungen Geeignet für große Sammlungen oder Operationen, die frühzeitig abgebrochen werden können (take, find, first, any, all, none)

Die Verwendung von Standardfunktionen auf Sammlungen ist meist ausreichend und kürzer. Sequenzen werden empfohlen, wenn explizite Faulheit zur Leistungsoptimierung bei der Arbeit mit großen Datenmengen erforderlich ist.