forEach so với forEachOrdered trong Java 8 Stream


86

Tôi hiểu rằng các phương pháp này khác nhau về thứ tự thực hiện nhưng trong tất cả các thử nghiệm của tôi, tôi không thể đạt được thứ tự thực hiện khác nhau.

Thí dụ:

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));

Đầu ra:

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

Vui lòng cung cấp ví dụ khi 2 phương pháp sẽ tạo ra kết quả đầu ra khác nhau.


Có thể thử với các luồng song song.
Pshemo

@Pshemo có phải là lựa chọn duy nhất khả thi không?
gstackoverflow

5
Đơn hàng không xác định không có nghĩa là “được đảm bảo là đơn hàng khác”. Nó chỉ có nghĩa là không xác định , luôn ngụ ý khả năng khớp với thứ tự cuộc gặp gỡ. Không có chức năng xáo trộn tích hợp.
Holger

Câu trả lời:


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));

Dòng thứ hai sẽ luôn xuất ra

Output:AAA
Output:BBB
Output:CCC

trong khi cái đầu tiên không được đảm bảo vì đơn đặt hàng không được giữ. forEachOrderedsẽ xử lý các phần tử của luồng theo thứ tự được chỉ định bởi nguồn của nó, bất kể luồng là tuần tự hay song song.

Trích dẫn từ forEachJavadoc:

Hành vi của hoạt động này rõ ràng là không xác định. Đối với các đường ống dòng song song, thao tác này không đảm bảo tôn trọng thứ tự gặp gỡ của dòng, vì làm như vậy sẽ hy sinh lợi ích của chế độ song song.

Khi forEachOrderedJavadoc trạng thái (nhấn mạnh của tôi):

Thực hiện một hành động cho mỗi phần tử của luồng này, theo thứ tự gặp gỡ của luồng nếu luồng có một thứ tự gặp được xác định.


6
Vâng, bạn đã đúng. Có thể chỉ cho dòng song song không?
gstackoverflow

6
Ngay cả khi nó chỉ áp dụng cho các luồng song song ngay bây giờ - và tôi không nói là có - nó vẫn có thể bị hỏng trong tương lai nếu một số bước trung gian được tối ưu hóa để tận dụng các luồng không có thứ tự, ví dụ: một loại có thể sử dụng thuật toán không ổn định nếu luồng không có thứ tự.
the8472

1
Vì vậy, nó không có ý nghĩa để sử dụng forEachOrderedvới parallel?
Bhushan

3
@BhushanPatil Vâng, chính xác. stackoverflow.com/questions/47336825/…
Sagar

1
Sử dụng forEachOrdered sẽ xử lý phần tử theo thứ tự sau đó sử dụng các luồng song song sẽ làm mất đi lợi ích của song song. Hãy đề nghị.
Deepak

30

Mặc dù forEachngắn hơn và trông đẹp hơn, tôi khuyên bạn nên sử dụng forEachOrderedở mọi nơi mà thứ tự quan trọng để chỉ định rõ ràng điều này. Đối với các luồng tuần tự, forEachcó vẻ như tôn trọng thứ tự và thậm chí sử dụng mã nội bộ API luồng forEach(đối với luồng được biết là tuần tự) khi cần sử dụng về mặt ngữ nghĩa forEachOrdered! Tuy nhiên, sau đó bạn có thể quyết định thay đổi luồng của mình thành song song và mã của bạn sẽ bị hỏng. Ngoài ra khi bạn sử dụng forEachOrderedtrình đọc mã của bạn sẽ thấy thông báo: "đơn hàng quan trọng ở đây". Vì vậy nó ghi lại mã của bạn tốt hơn.

Cũng lưu ý rằng đối với các luồng song song, forEachkhông chỉ được thực thi theo thứ tự không xác định, mà bạn còn có thể thực thi nó đồng thời trong các luồng khác nhau cho các phần tử khác nhau (điều này là không thể với forEachOrdered).

Cuối cùng cả hai forEach/ forEachOrderedhiếm khi hữu ích. Trong hầu hết các trường hợp, bạn thực sự cần tạo ra một số kết quả, không chỉ là tác dụng phụ, do đó các hoạt động giống reducehoặc collectphải phù hợp hơn. Thể hiện hoạt động giảm thiểu thông qua forEachthường được coi là một phong cách tồi.


7
"Cuối cùng, cả forEach / forEachOrdered đều hiếm khi hữu ích". Tôi không thể đồng ý thêm nữa. Có vẻ như những phương pháp này đã được sử dụng quá mức.
Tunaki

Cảm ơn về câu trả lời. nhưng nó không phải là ví dụ cuộc sống thực. Tôi chỉ cần tìm hiểu java 8
gstackoverflow

Tại sao nó cần thiết về mặt ngữ nghĩa để sử dụng forEachOrderedtrong mã đó?
RealSkeptic

1
@RealSkeptic, đó là luồng do người dùng chỉ định (được chuyển vào flatMap). Nó có thể được đặt hàng, vì vậy nó phải được đặt vào luồng kết quả theo cùng một thứ tự.
Tagir Valeev

2
@RealSkeptic, bạn là người hoài nghi thực sự! Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)trả về true, do đó thứ tự cho luồng kết quả phải được xác định. Nếu bạn cảm thấy rằng tài liệu JDK nên nói rõ ràng về điều này, vui lòng gửi lỗi.
Tagir Valeev

15

forEach()phương thức thực hiện một hành động cho mỗi phần tử của luồng này. Đối với luồng song song, thao tác này không đảm bảo duy trì trật tự của luồng.

forEachOrdered() phương thức thực hiện một hành động cho mỗi phần tử của luồng này, đảm bảo rằng mỗi phần tử được xử lý theo thứ tự gặp đối với các luồng có thứ tự gặp được xác định.

lấy ví dụ dưới đây:

    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));

Đầu ra:

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

sushil mittal

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

mihul issltat

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

sushil mittal
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.