Como trabalhar com streams em Kotlin?
sobes.tech IA
Resposta da IA
Em Kotlin, para trabalhar com fluxos de dados (equivalente à Java 8 Streams API), utilizam-se funções de extensão para coleções fornecidas pela biblioteca de funções padrão. Não é uma API separada, mas um conjunto de métodos em kotlin.collections.
As operações principais com fluxos dividem-se em:
- Operações intermédias: Devolvem uma nova coleção e são "preguiçosas" (só se executam ao chamar uma operação terminal). Exemplos:
filter,map,flatMap,distinct,sorted,take,drop. - Operações terminais: Finalizam a sequência de operações e devolvem um resultado (não uma coleção). Disparam a execução de todas as operações intermédias. Exemplos:
forEach,reduce,fold,count,sum,average,min,max,toList,toSet,toMap.
Existe também o conceito de sequências (sequences), que fornece uma preguiça explícita. As sequências processam os elementos um a um conforme necessário, o que pode ser mais eficiente para coleções grandes ou cadeias longas de operações:
- Criação de uma sequência:
collection.asSequence() - Conversão de volta para coleção:
sequence.toList()
// Exemplo de uso de funções padrão para processamento em fluxo
fun processCollection() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val evenSquares = numbers
.filter { it % 2 == 0 } // Operação intermédia: filtrar números pares
.map { it * it } // Operação intermédia: elevar ao quadrado
println(evenSquares) // Operação terminal: mostrar a coleção (executa filter e map)
val sumOfOdd = numbers
.filter { it % 2 != 0 } // Intermédia
.sum() // Terminal (calcula a soma dos ímpares)
println(sumOfOdd)
}
// Exemplo de uso de sequências
fun processSequence() {
val largeCollection = (1..1_000_000).toList()
// Com coleções (não preguiçosas): filter e map executam-se para todos os elementos imediatamente
val resultCollection = largeCollection
.filter { it % 2 == 0 }
.map { it * 2 }
.take(10) // take(10) executa-se após filter e map para todos
println("Tamanho da coleção resultado: ${resultCollection.size}")
// Com sequências (preguiçosas): filter, map e take executam-se elemento por elemento
val resultSequence = largeCollection.asSequence()
.filter { it % 2 == 0 } // filter executa para cada elemento em ordem
.map { it * 2 } // map executa para cada elemento que passa o filtro
.take(10) // take(10) para o processamento após 10 elementos
println("Tamanho da sequência resultado: ${resultSequence.toList().size}") // toList() dispara a execução da sequência
}
fun main() {
processCollection()
processSequence()
}
Tabela comparativa de funções padrão e sequências relativamente à preguiça:
| Característica | Funções padrão de coleções | Sequências |
|---|---|---|
| Preguiça | Preguiça implícita para operações intermédias, mas a operação terminal processa toda a cadeia intermédia | Preguiça explícita: as operações executam-se elemento por elemento conforme necessário |
| Eficiência | Pode ser menos eficiente para grandes coleções e cadeias longas de operações devido às coleções intermédias | Mais eficiente para grandes coleções e cadeias longas de operações |
| Aplicação | Adequado para coleções pequenas e médias | Adequado para grandes coleções ou operações que podem ser interrompidas cedo (take, find, first, any, all, none) |
O uso de funções padrão em coleções é geralmente suficiente e mais conciso. Sequências são recomendadas quando é necessária uma preguiça explícita para otimizar o desempenho ao trabalhar com grandes volumes de dados.