🔁 1. Operações não determinísticas
- Operações como forEach e findAny não garantem ordem em parallelStream.
- Isso pode melhorar a performance, mas o resultado pode mudar em cada execução.
📌 Exemplo com forEach (não garante ordem):
List numeros = Arrays.asList(1, 2, 3, 4, 5);
numeros.parallelStream()
.forEach(System.out::print); // Pode imprimir: 23145, 51324, etc.
✅ Exemplo com forEachOrdered (garante ordem):
numeros.parallelStream()
.forEachOrdered(System.out::print); // Sempre: 12345
🔍 2. findAny vs findFirst
- findAny() retorna qualquer elemento, sem ordem garantida.
- findFirst() sempre retorna o primeiro elemento, respeitando a ordem do stream.
🔁 Exemplo:
Optional qualquer = numeros.parallelStream().findAny();
Optional primeiro = numeros.parallelStream().findFirst();
📌 3. Ordered vs Unordered Streams
- Streams de listas (List, LongStream.range) são ordenados por padrão.
- HashSet, por exemplo, não tem ordem definida.
- Usar unordered() pode melhorar a performance em paralelismo.
🔁 Exemplo:
Set conjunto = new HashSet<>(Arrays.asList(1, 2, 3));
conjunto.parallelStream()
.unordered()
.map(x -> x + 1)
.forEach(System.out::println); // Pode imprimir: 4, 2, 3
🧩 4. Coletor agrupador paralelo
- Collectors.groupingBy() mantém a ordem, mas pode ser lento em paralelo.
- Collectors.groupingByConcurrent() não garante a ordem, mas é mais rápido.
🧪 Exemplo:
Map> agrupado = numeros.parallelStream()
.collect(Collectors.groupingBy(i -> i % 2 == 0)); // Mantém ordem
Map> agrupadoConcurrente = numeros.parallelStream()
.collect(Collectors.groupingByConcurrent(i -> i % 2 == 0)); // Melhor performance
⚠️ 5. Efeitos colaterais e variáveis compartilhadas
Usar variáveis compartilhadas em streams paralelos pode causar resultados incorretos.
😵 Exemplo inseguro:
class UnsafeParallelStreamUsage {
private static long total = 0;
public static void main(String... args) {
LongStream.range(0, 1_000_000_000)
.parallel()
.filter(x -> x % 2 == 0)
.forEach(n -> total += n); // ERRO! Concorrência não segura
System.out.println(total); // Resultados diferentes a cada execução
}
}
✅ Em vez disso, use sum() ou reduce() que são operações seguras:
long total = LongStream.range(0, 1_000_000_000)
.parallel()
.filter(x -> x % 2 == 0)
.sum(); // Correto
🧠 6. O que é um Spliterator?
- É uma versão moderna do Iterator, quebrável em partes.
- Permite que várias threads processem partes diferentes do stream.
- A paralelização do Stream se baseia nele junto com a API Fork/Join.
Classe de Exemplo completo no repo: ExemploOperacoesStreams