Ambas as interfaces definem apenas um método
public operator fun iterator(): Iterator<T>
A documentação diz que Sequence
é para ser preguiçoso. Mas também não é Iterable
preguiçoso (a menos que seja apoiado por a Collection
)?
fonte
Ambas as interfaces definem apenas um método
public operator fun iterator(): Iterator<T>
A documentação diz que Sequence
é para ser preguiçoso. Mas também não é Iterable
preguiçoso (a menos que seja apoiado por a Collection
)?
A principal diferença reside na semântica e na implementação das funções de extensão stdlib para Iterable<T>
e Sequence<T>
.
Pois Sequence<T>
, as funções de extensão executam lentamente onde possível, de forma semelhante às operações intermediárias do Java Streams . Por exemplo, Sequence<T>.map { ... }
retorna outro Sequence<R>
e não processa realmente os itens até que uma operação de terminal como toList
ou fold
seja chamada.
Considere este código:
val seq = sequenceOf(1, 2)
val seqMapped: Sequence<Int> = seq.map { print("$it "); it * it } // intermediate
print("before sum ")
val sum = seqMapped.sum() // terminal
Ele imprime:
before sum 1 2
Sequence<T>
destina-se a uso lento e pipelining eficiente quando você deseja reduzir o trabalho feito em operações de terminal tanto quanto possível, o mesmo para Java Streams. No entanto, a preguiça introduz alguma sobrecarga, o que é indesejável para transformações simples comuns de coleções menores e as torna menos eficientes.
Em geral, não há uma boa maneira de determinar quando ele é necessário, portanto, no Kotlin stdlib, a preguiça é explicitada e extraída para a Sequence<T>
interface para evitar o uso em todos os programas Iterable
por padrão.
Pois Iterable<T>
, ao contrário, as funções de extensão com semântica de operação intermediária funcionam avidamente, processam os itens imediatamente e retornam outro Iterable
. Por exemplo, Iterable<T>.map { ... }
retorna um List<R>
com os resultados do mapeamento nele.
O código equivalente para Iterable:
val lst = listOf(1, 2)
val lstMapped: List<Int> = lst.map { print("$it "); it * it }
print("before sum ")
val sum = lstMapped.sum()
Isso imprime:
1 2 before sum
Como dito acima, Iterable<T>
não é preguiçoso por padrão, e esta solução mostra-se bem: na maioria dos casos tem boa localidade de referência , tirando proveito do cache da CPU, predição, pré-busca etc. para que mesmo a cópia múltipla de uma coleção ainda funcione o suficiente e tem melhor desempenho em casos simples com pequenas coleções.
Se você precisar de mais controle sobre o pipeline de avaliação, há uma conversão explícita para uma sequência preguiçosa com Iterable<T>.asSequence()
função.
Java
(principalmenteGuava
)map
,filter
e outros não carregam informações suficientes para decidir além do tipo de coleção de origem, e uma vez que a maioria das coleções também são Iteráveis, isso não é um bom marcador para "ser preguiçoso" porque é comumente EM TODOS OS LUGARES. preguiçoso deve ser explícito para ser seguro.Concluindo a resposta da tecla de atalho:
É importante observar como Sequence e Iterable itera em todos os seus elementos:
Exemplo de sequência:
list.asSequence().filter { field -> Log.d("Filter", "filter") field.value > 0 }.map { Log.d("Map", "Map") }.forEach { Log.d("Each", "Each") }
Resultado do log:
filtro - Mapa - Cada; filtro - Mapa - Cada
Exemplo iterável:
list.filter { field -> Log.d("Filter", "filter") field.value > 0 }.map { Log.d("Map", "Map") }.forEach { Log.d("Each", "Each") }
filtro - filtro - Mapa - Mapa - Cada - Cada
fonte
Você pode encontrar mais aqui .
fonte