forEach vs forEachOrdered no Java 8 Stream

86

Eu entendo que esses métodos diferem na ordem de execução, mas em todos os meus testes não consigo obter execução de ordem diferente.

Exemplo:

System.out.println("forEach Demo");
Stream.of("AAA","BBB","CCC").forEach(s->System.out.println("Output:"+s));
System.out.println("forEachOrdered Demo");
Stream.of("AAA","BBB","CCC").forEachOrdered(s->System.out.println("Output:"+s));

Resultado:

forEach Demo
Output:AAA
Output:BBB
Output:CCC
forEachOrdered Demo
Output:AAA
Output:BBB
Output:CCC

Forneça exemplos quando 2 métodos produzirão resultados diferentes.

gstackoverflow
fonte
Tente talvez com fluxos paralelos.
Pshemo
@Pshemo é a única opção possível?
gstackoverflow
5
O pedido não especificado não significa “garantia de um pedido diferente”. Significa apenas não especificado , o que sempre implica a possibilidade de combinar a ordem do encontro. Não há função de reprodução aleatória integrada.
Holger

Respostas:

89
Stream.of("AAA","BBB","CCC").parallel().forEach(s->System.out.println("Output:"+s));
Stream.of("AAA","BBB","CCC").parallel().forEachOrdered(s->System.out.println("Output:"+s));

A segunda linha sempre produzirá

Output:AAA
Output:BBB
Output:CCC

enquanto o primeiro não é garantido, pois a ordem não é mantida. forEachOrderedirá processar os elementos do fluxo na ordem especificada por sua fonte, independentemente de o fluxo ser sequencial ou paralelo.

Citando de forEachJavadoc:

O comportamento desta operação é explicitamente não determinístico. Para pipelines de stream paralelos, essa operação não garante o respeito à ordem de encontro do stream, pois isso sacrificaria o benefício do paralelismo.

Quando o forEachOrderedJavadoc afirma (ênfase minha):

Executa uma ação para cada elemento deste fluxo, na ordem de encontro do fluxo se o fluxo tiver uma ordem de encontro definida.

Tunaki
fonte
6
Sim você está certo. É possível apenas para parallelStreams?
gstackoverflow
6
Mesmo que só se aplique a streams paralelos agora - e não estou dizendo que se aplica - ainda pode quebrar no futuro se algumas etapas intermediárias forem otimizadas para tirar proveito de streams não ordenados, por exemplo, uma classificação poderia usar um algoritmo instável se o fluxo está desordenado.
the8472
1
Portanto, não faz sentido usar forEachOrderedcom parallel?
Bhushan
3
@BhushanPatil Sim, correto. stackoverflow.com/questions/47336825/…
Sagar
1
Usar forEachOrdered processará elemento por pedido e, em seguida, usará fluxos paralelos perderá os benefícios do paralelismo. Por favor sugira.
Deepak
30

Embora forEachmais curto e pareça mais bonito, eu sugiro usar forEachOrderedem todos os lugares onde a ordem é importante para especificar isso explicitamente. Para fluxos sequenciais, forEachparece respeitar a ordem e até mesmo usar o código interno da API de fluxo forEach(para fluxos sabidamente sequenciais) onde é semanticamente necessário usar forEachOrdered! No entanto, você pode decidir posteriormente alterar seu fluxo para paralelo e seu código será quebrado. Além disso, quando você usa forEachOrderedo leitor de seu código, vê a mensagem: "a ordem é importante aqui". Assim, documenta melhor o seu código.

Observe também que, para fluxos paralelos, forEachnão apenas é executado em ordem não determinística, mas também pode ser executado simultaneamente em diferentes threads para diferentes elementos (o que não é possível com forEachOrdered).

Finalmente, ambos forEach/ forEachOrderedraramente são úteis. Na maioria dos casos, você realmente precisa produzir algum resultado, não apenas efeito colateral, portanto, operações semelhantes reduceou collectdevem ser mais adequadas. Expressar a operação de redução natural via forEachgeralmente é considerado um estilo ruim.

Tagir Valeev
fonte
7
"Finalmente, ambos forEach / forEachOrdered raramente são úteis". Eu não poderia concordar mais. Parece que esses métodos são usados ​​em demasia.
Tunaki
Obrigado pela resposta. mas não é um exemplo da vida real. Acabei de aprender java 8
gstackoverflow
Por que é semanticamente necessário usar forEachOrderednesse código?
RealSkeptic
1
@RealSkeptic, é o fluxo especificado pelo usuário (passado para flatMap). Ele pode ser ordenado, portanto, deve ser colocado no fluxo resultante na mesma ordem.
Tagir Valeev
2
@RealSkeptic, você é o verdadeiro cético! Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)retorna true, portanto, a ordem do fluxo resultante deve ser determinada. Se você acha que a documentação do JDK deve dizer explicitamente sobre isso, sinta-se à vontade para enviar um bug.
Tagir Valeev
15

forEach()método executa uma ação para cada elemento deste fluxo. Para fluxo paralelo, esta operação não garante a manutenção da ordem do fluxo.

forEachOrdered() O método executa uma ação para cada elemento desse fluxo, garantindo que cada elemento seja processado em ordem de encontro para fluxos que tenham uma ordem de encontro definida.

veja o exemplo abaixo:

    String str = "sushil mittal";
    System.out.println("****forEach without using parallel****");
    str.chars().forEach(s -> System.out.print((char) s));
    System.out.println("\n****forEach with using parallel****");

    str.chars().parallel().forEach(s -> System.out.print((char) s));
    System.out.println("\n****forEachOrdered with using parallel****");

    str.chars().parallel().forEachOrdered(s -> System.out.print((char) s));

Resultado:

****forEach without using parallel****

sushil mittal

****forEach with using parallel****

mihul issltat

****forEachOrdered with using parallel****

sushil mittal
Sushil Mittal
fonte