Às vezes, você deseja filtrar um Stream
com mais de uma condição:
myList.stream().filter(x -> x.size() > 10).filter(x -> x.isCool()) ...
ou você pode fazer o mesmo com uma condição complexa e uma única filter
:
myList.stream().filter(x -> x.size() > 10 && x -> x.isCool()) ...
Meu palpite é que a segunda abordagem tem melhores características de desempenho, mas eu não sei .
A primeira abordagem ganha em legibilidade, mas o que é melhor para o desempenho?
Respostas:
O código que deve ser executado para ambas as alternativas é tão semelhante que você não pode prever um resultado com confiabilidade. A estrutura do objeto subjacente pode ser diferente, mas isso não é um desafio para o otimizador de hotspot. Portanto, depende de outras condições circundantes que renderão uma execução mais rápida, se houver alguma diferença.
A combinação de duas instâncias de filtro cria mais objetos e, portanto, mais código de delegação, mas isso pode mudar se você usar referências de método em vez de expressões lambda, por exemplo, substituir
filter(x -> x.isCool())
porfilter(ItemType::isCool)
. Dessa forma, você eliminou o método de delegação sintético criado para sua expressão lambda. Portanto, combinar dois filtros usando duas referências de método pode criar o mesmo ou menor código de delegação do que uma únicafilter
chamada usando uma expressão lambda com&&
.Mas, como dito, esse tipo de sobrecarga será eliminado pelo otimizador HotSpot e é insignificante.
Em teoria, dois filtros poderiam ser mais facilmente paralelizados do que um único filtro, mas isso é relevante apenas para tarefas intensas computacionais¹.
Portanto, não há uma resposta simples.
A conclusão é que não pense nessas diferenças de desempenho abaixo do limite de detecção de odores. Use o que for mais legível.
¹… e exigiria uma implementação que processe paralelamente os estágios subsequentes, uma estrada atualmente não tomada pela implementação padrão do Stream
fonte
Uma condição de filtro complexa é melhor na perspectiva do desempenho, mas o melhor desempenho mostra a moda antiga para loop com um padrão
if clause
é a melhor opção. A diferença em uma matriz pequena A diferença de 10 elementos pode ~ 2 vezes, para uma matriz grande a diferença não é tão grande.Você pode dar uma olhada no meu projeto GitHub , onde fiz testes de desempenho para várias opções de iteração de matriz
Para ops / s de taxa de transferência de 10 elementos de matriz pequena: Para ops / s de taxa de transferência de 10.000 elementos médios : Para ops / s de taxa de transferência de 10.000 elementos médios :
NOTA: os testes são executados em
UPDATE: Java 11 tem algum progresso no desempenho, mas a dinâmica permanece a mesma
Modo de referência: taxa de transferência, ops / time
fonte
Este teste mostra que sua segunda opção pode ter um desempenho significativamente melhor. Resultados primeiro, depois o código:
agora o código:
fonte
Test #1: {count=100, sum=7207, min=65, average=72.070000, max=91} Test #3: {count=100, sum=7959, min=72, average=79.590000, max=97} Test #2: {count=100, sum=8869, min=79, average=88.690000, max=110}
Este é o resultado das 6 combinações diferentes do teste de amostra compartilhado pelo @Hank D É evidente que o predicado de forma
u -> exp1 && exp2
é de alto desempenho em todos os casos.fonte