In Kotlin, Sequence è una sequenza pigra che consente di lavorare in modo efficiente con grandi o addirittura potenzialmente infinite raccolte di dati. Le operazioni su Sequence (ad esempio, map, filter) non vengono eseguite immediatamente; invece, viene costruita una catena di azioni e il calcolo avviene solo quando necessario (in un'operazione terminale, ad esempio, toList).
Perché è importante:
Esempio di codice:
val numbers = generateSequence(1) { it + 1 } .filter { it % 2 == 0 } .map { it * it } .take(5) .toList() println(numbers) // [4, 16, 36, 64, 100]
In questo esempio, solo i primi 5 elementi della sequenza verranno realmente computati, nonostante sia potenzialmente infinita.
Quando utilizzare Sequence:
È possibile garantire che operatori come
mapefilternelle collezioni normali di Kotlin siano anch'essi pigri? Perché?
Risposta: No, le operazioni sulle collezioni standard (List.map, List.filter, ecc.) in Kotlin sono stricte e golose. Ogni operazione crea una collezione intermedia e elabora immediatamente tutti gli elementi. La pigrizia è supportata solo quando si utilizza Sequence.
Esempio:
val data = listOf(1,2,3,4) val mapped = data.map { println("Mapping $it"); it * 2 } // Stampa immediatamente tutti i valori
Storia
In un progetto che elabora grandi file CSV (fino a un gigabyte per scrittura), la collezione veniva inizialmente caricata completamente in una List, dopo di che venivano applicate catene di map/filter. L'applicazione ‘falliva’ per OutOfMemory — il problema è stato risolto sostituendo List con Sequence, il cui map/filter non creava enormi liste intermedie.
Storia
Un servizio backend per aggregare report da molti database inizialmente accumulava i risultati della ricerca in una List e poi filtrava: le richieste divennero lente, si osservavano ritardi di GC. La sostituzione con un generatore + Sequence ha permesso l'aggregazione dei dati al volo, riducendo i ritardi di diversi ordini di grandezza.
Storia
Un progetto migrato da Java utilizzava le estensioni standard di Kotlin (map, filter) senza passare a Sequence quando lavorava con grandi flussi di dati, supponendo che il codice funzionasse in modo pigro, come i flussi di Java 8. L'errore portava a gravi perdite di memoria e a malfunzionamenti improvvisi in produzione.