Cách peek () và allMatch () hoạt động cùng nhau trong API luồng Java 8


10

Tôi đã tìm thấy một câu đố về phương pháp API của Java 8 Stream như bên dưới

Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));

Đầu ra là

Fred
Jim

Tôi bối rối làm thế nào luồng này hoạt động? Kết quả mong đợi của tôi sẽ là

Fred
Jim
Sheila

Phương thức peek () là một hoạt động trung gian và nó xử lý từng phần tử trong Luồng. Bất cứ ai có thể giải thích cho tôi điều này.

Câu trả lời:


10

Đó là một tối ưu hóa luồng được gọi là ngắn mạch. Về cơ bản, những gì xảy ra là allMatchngăn chặn việc thực hiện các hoạt động trung gian không cần thiết trên luồng, bởi vì không có điểm nào trong việc thực hiện chúng khi biết kết quả cuối cùng.

Như thể điều này đã xảy ra:

take"Fred"
peek("Fred")
evaluate("Fred".startsWith("F"))
decide whether the result of allMatch() is known for sure: Not yet

take"Jim"
peek("Jim")
evaluate("Jim".startsWith("F"))
decide whether the result of allMatch() is known for sure: Yes

Khi "Jim".startsWith("F")được đánh giá, kết quả allMatch(s -> s.startsWith("F"))được biết đến nhất định. Không quan trọng giá trị nào xuất hiện trong đường ống sau đó "Jim", chúng tôi biết rằng tất cả các giá trị bắt đầu bằng "F" là sai

Điều này không đặc trưng cho sự kết hợp peek/ allMatch, có nhiều hoạt động ngắn mạch trung gian và đầu cuối. java.util.streamgói tài liệu trạng thái:

Hơn nữa, một số hoạt động được coi là hoạt động ngắn mạch. Một hoạt động trung gian là ngắn mạch nếu, khi được trình bày với đầu vào vô hạn, kết quả là nó có thể tạo ra một luồng hữu hạn. Một hoạt động đầu cuối là ngắn mạch nếu, khi được trình bày với đầu vào vô hạn, nó có thể chấm dứt trong thời gian hữu hạn. Có một hoạt động ngắn mạch trong đường ống là điều kiện cần, nhưng không đủ, để xử lý một luồng vô hạn để chấm dứt bình thường trong thời gian hữu hạn.

Mở rộng điều này đến các luồng hữu hạn và các hoạt động ngắn mạch làm cản trở việc thực hiện các bước đường ống không cần thiết, như trong trường hợp ví dụ của bạn.


5
Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
  • Lần đầu tiên thông qua, Fredđược in. Nó rất hợp
  • Lần thứ hai thông qua, Jimđược in. Nó không khớp nên allMatch chấm dứt vì "Tất cả không khớp"
  • Vì vậy, mục cuối cùng không được tiêu thụ từ luồng.

3

Các tài liệu cho peekphương thức nói (nhấn mạnh của tôi):

Trả về một luồng bao gồm các phần tử của luồng này, ngoài ra thực hiện hành động được cung cấp trên mỗi phần tử khi các phần tử được tiêu thụ từ luồng kết quả .

Vì vậy, trong trường hợp này, peekkhông thấy "Sheila"vì giá trị đó không được tiêu thụ từ luồng. Ngay sau khi "Jim"được tiêu thụ, kết quả .allMatch(s -> s.startsWith("F"))đã được biết đến false, do đó không cần phải tiêu thụ thêm bất kỳ yếu tố nào từ luồng.


1

Theo tài liệu Java của allMatch ():

Trả về việc tất cả các thành phần của luồng này có khớp với vị từ được cung cấp hay không. Có thể không đánh giá vị ngữ trên tất cả các yếu tố nếu không cần thiết để xác định kết quả. Nếu luồng trống thì {@code true} được trả về và vị từ không được ước tính.

@apiNote

Phương pháp này đánh giá định lượng phổ quát của vị từ trên các phần tử của luồng (với mọi x P (x)). Nếu luồng trống, việc định lượng được cho là thỏa mãn một cách trống rỗng và luôn luôn là {@code true} (bất kể P (x)).

biến vị ngữ để áp dụng cho các phần tử của luồng này @return {@code true} nếu tất cả các phần tử của luồng khớp với vị từ được cung cấp hoặc luồng trống, nếu không {@code false}

Trong trường hợp của bạn:

1-

p(x) : s -> s.startsWith("F")

X : "Fred"

result : X P(X) = true

2-

p(x) : s -> s.startsWith("F")

X : "Jim"

result : X P(X) = false

Không có đánh giá nào nữa sẽ diễn ra, vì XP (X) = false

boolean result = Arrays.asList("Fred", "Finda", "Fish")
            .stream()
            .peek(System.out::println)
            .allMatch(s -> s.startsWith("F"));
    System.out.println("Result "+result);

Đầu ra là:

Fred
Finda
Fish
Result true

Ở đây luồng xử lý hoàn toàn vì xP (x) = true từ mỗi phần tử

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.