Sou iniciante no Java 8. Ainda não conheço a API em profundidade, mas fiz uma pequena referência informal para comparar o desempenho da nova API do Streams com as boas e antigas coleções.
O teste consiste em filtrar uma lista de Integer
, e para cada número par, calcular a raiz quadrada e armazená-la no resultado List
de Double
.
Aqui está o código:
public static void main(String[] args) {
//Calculating square root of even numbers from 1 to N
int min = 1;
int max = 1000000;
List<Integer> sourceList = new ArrayList<>();
for (int i = min; i < max; i++) {
sourceList.add(i);
}
List<Double> result = new LinkedList<>();
//Collections approach
long t0 = System.nanoTime();
long elapsed = 0;
for (Integer i : sourceList) {
if(i % 2 == 0){
result.add(Math.sqrt(i));
}
}
elapsed = System.nanoTime() - t0;
System.out.printf("Collections: Elapsed time:\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
//Stream approach
Stream<Integer> stream = sourceList.stream();
t0 = System.nanoTime();
result = stream.filter(i -> i%2 == 0).map(i -> Math.sqrt(i)).collect(Collectors.toList());
elapsed = System.nanoTime() - t0;
System.out.printf("Streams: Elapsed time:\t\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
//Parallel stream approach
stream = sourceList.stream().parallel();
t0 = System.nanoTime();
result = stream.filter(i -> i%2 == 0).map(i -> Math.sqrt(i)).collect(Collectors.toList());
elapsed = System.nanoTime() - t0;
System.out.printf("Parallel streams: Elapsed time:\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
}.
E aqui estão os resultados para uma máquina com núcleo duplo:
Collections: Elapsed time: 94338247 ns (0,094338 seconds)
Streams: Elapsed time: 201112924 ns (0,201113 seconds)
Parallel streams: Elapsed time: 357243629 ns (0,357244 seconds)
Para este teste específico, os fluxos são duas vezes mais lentos que as coleções e o paralelismo não ajuda (ou estou usando da maneira errada?).
Questões:
- Este teste é justo? Eu cometi algum erro?
- Os fluxos são mais lentos que as coleções? Alguém fez uma boa referência formal sobre isso?
- Qual abordagem devo buscar?
Resultados atualizados.
Fiz o teste 1k vezes após o aquecimento da JVM (1k iterações), conforme recomendado por @pveentjer:
Collections: Average time: 206884437,000000 ns (0,206884 seconds)
Streams: Average time: 98366725,000000 ns (0,098367 seconds)
Parallel streams: Average time: 167703705,000000 ns (0,167704 seconds)
Nesse caso, os fluxos são mais eficientes. Gostaria de saber o que seria observado em um aplicativo em que a função de filtragem é chamada apenas uma ou duas vezes durante o tempo de execução.
toList
deve ser executado em paralelo, mesmo que esteja coletando em uma lista que não seja segura para threads, pois os diferentes threads serão coletados em listas intermediárias restritas a threads antes de serem mesclados.
IntStream
?