2017-10-09 20 views
45

Để cố gắng tìm hiểu sâu suối java và spliterators, Tôi có một số câu hỏi tế nhị về đặc spliterator:Hiểu sâu sắc đặc điểm spliterator

Q1: Stream.empty() vs Stream.of() (Stream.of() mà không args)

  • Stream.empty(): SUBSIZED, VỪA
  • Stream.of(): SUBSIZED, bất biến, VỪA, LỆNH

Tại sao Stream.empty() không có đặc điểm giống nhau của Stream.of()? Lưu ý rằng nó có tác động khi sử dụng kết hợp với Stream.concat() (đặc biệt không có ORDERED). Tôi có thể nói rằng Stream.empty() không chỉ có IMMUTABLE và ORDERED mà còn là DISTINCT và NONNULL. Ngoài ra nó có ý nghĩa Stream.of() với chỉ một đối số có DISTICT.

Q2: LongStream.of() không có NONNULL

Chỉ cần nhận thấy rằng NONNULL không có sẵn trong LongStream.of. Không phải là NONNULL một đặc điểm chính của tất cả LongStream s, IntStream s và DoubleStream s?

Q3: LongStream.range(,) vs LongStream.range(,).boxed()

  • LongRange.range(,): SUBSIZED, bất biến, NONNULL, VỪA, RA LỆNH, sắp xếp, DISTINCT
  • LongStream.range(,).boxed(): SUBSIZED, VỪA, RA LỆNH

Tại sao .boxed() mất tất cả các đặc tính này? Nó không nên mất bất kỳ.

Tôi hiểu rằng .mapToObj() có thể mất NONNULL, IMMUTABLE và DISTICT, nhưng .boxed() ... không có ý nghĩa.

Q4: .peek() mất bất biến và NONNULL

LongStream.of(1): SUBSIZED, bất biến, NONNULL, VỪA ... LongStream.of(1).peek(): SUBSIZED, VỪA, ...

Tại sao .peek() mất các đặc điểm này? .peek không thực sự mất bất kỳ.

Q5: .skip(), .limit() mất SUBSIZED, bất biến, NONNULL, VỪA

Chỉ cần nhận thấy rằng các hoạt động này mất SUBSIZED, bất biến, NONNULL, VỪA. Tại sao? Nếu kích thước có sẵn, thì thật dễ dàng để tính toán kích thước cuối cùng.

Q6: .filter() mất bất biến, NONNULL

Chỉ cần nhận thấy rằng hoạt động này mất cũng SUBSIZED, bất biến, NONNULL, VỪA. Việc mất được phân loại và SIZED có ý nghĩa, nhưng hai cách khác không có ý nghĩa. Tại sao?


Tôi sẽ đánh giá cao nếu ai đó hiểu sâu sắc về trình tách biệt có thể mang lại sự rõ ràng. Cảm ơn.

+1

Ai đó đã bỏ phiếu để đóng câu hỏi là "quá rộng" và tôi đã bị cám dỗ làm điều tương tự vì có vẻ như sáu câu hỏi trong một câu hỏi. Mặt khác, có thể có một lời giải thích tổng thể cho tất cả các chi tiết này ... – Nicolai

+4

@Nicolai Tôi đã bỏ phiếu ban đầu ... nhưng quá tốt để đóng cửa, vì vậy tôi đã quay lại nó. Tôi thích điều này "tất cả-trong-một" cho một câu hỏi hay. Bên cạnh một vài người dùng Oracle (Stuart? Hoặc Brian?), Tôi chỉ mong Holger biết chính xác nội tại của những thứ này. Vui vẻ chờ đợi. :) – Eugene

+0

* Tôi hiểu rằng '.mapToObj()' có thể mất NONNULL, IMMUTABLE và DISTI [N] CT *. Tại sao không SORTED? – shmosel

Trả lời

31

Tôi phải thừa nhận rằng tôi cũng gặp khó khăn khi lần đầu tiên tìm hiểu ý nghĩa thực tế của các đặc điểm và cảm giác rằng ý nghĩa của chúng không được giải quyết rõ ràng trong giai đoạn thực hiện Java 8 và được sử dụng không nhất quán cho điều đó lý do.

Cân nhắc Spliterator.IMMUTABLE:

giá trị đặc trưng có nghĩa rằng nguồn yếu tố không thể được sửa đổi về mặt cấu trúc; có nghĩa là, các phần tử không thể được thêm vào, thay thế hoặc loại bỏ, do đó những thay đổi như vậy không thể xảy ra trong quá trình truyền tải.

Thật kỳ lạ để xem “thay thế” trong danh sách này, mà thường không được coi là một sự sửa đổi cấu trúc khi nói về một List hoặc một mảng và do đó, suối và spliterator nhà máy chấp nhận một mảng báo cáo (có nghĩa là không nhân bản) IMMUTABLE, như LongStream.of(…) hoặc Arrays.spliterator(long[]).

Nếu chúng ta giải thích điều này hào phóng hơn như “miễn là không thể quan sát được của khách hàng”, không có sự khác biệt đáng kể cho CONCURRENT, như trong cả hai trường hợp một số yếu tố sẽ được báo cáo cho khách hàng mà không cách nào để nhận ra liệu chúng được thêm vào trong quá trình truyền tải hoặc cho dù một số chưa được báo cáo do xóa, vì không có cách nào để tua lại một trình tách và so sánh.

Các đặc điểm kỹ thuật tiếp tục:

Một Spliterator mà không báo cáo IMMUTABLE hoặc CONCURRENT dự kiến ​​sẽ có một chính sách tài liệu (ví dụ ném ConcurrentModificationException) liên quan đến sự can thiệp về cấu trúc phát hiện trong quá traversal.

Và đó là điều duy nhất có liên quan, một spliterator báo cáo một trong hai, hoặc IMMUTABLECONCURRENT, đảm bảo sẽ không bao giờ ném một ConcurrentModificationException.Tất nhiên, CONCURRENT ngăn cản SIZED ngữ nghĩa, nhưng điều đó không có hậu quả đối với mã máy khách.

Thực tế, những đặc điểm này không được sử dụng cho bất kỳ thứ gì trong API luồng, do đó, việc sử dụng chúng không nhất quán sẽ không bao giờ được chú ý ở đâu đó.

Đây cũng là lời giải thích tại sao mỗi hoạt động trung gian có tác dụng xóa CONCURRENT, IMMUTABLENONNULL đặc điểm: việc thực hiện Dòng không sử dụng chúng và các lớp bên trong của nó đại diện cho nhà nước suối không duy trì chúng.


Tương tự như vậy, NONNULL không được sử dụng bất cứ nơi nào, vì vậy nó không có cho con suối nào đó không có tác dụng. Tôi có thể theo dõi các vấn đề LongStream.of(…) xuống để sử dụng nội bộ của Arrays.spliterator(long[], int, int) mà các đại biểu để
Spliterators.spliterator​(long[] array, int fromIndex, int toIndex, int additionalCharacteristics):

Các spliterator trở luôn luôn báo cáo đặc SIZEDSUBSIZED. Người gọi có thể cung cấp các đặc tính bổ sung cho trình phân tách để báo cáo. (Ví dụ: nếu biết rằng mảng sẽ không được sửa đổi thêm, hãy chỉ định IMMUTABLE; nếu dữ liệu mảng được coi là có lệnh bắt gặp, hãy chỉ định ORDERED). Phương pháp Arrays.spliterator(long[], int, int) thường có thể được sử dụng thay thế, trả về một trình tách biệt báo cáo SIZED, SUBSIZED, IMMUTABLEORDERED.

Lưu ý (lần nữa) việc sử dụng không nhất quán của đặc tính IMMUTABLE. Nó được xử lý lại giống như phải bảo đảm sự vắng mặt của bất kỳ sửa đổi nào, trong khi cùng lúc, Arrays.spliterator và lần lượt Arrays.streamLongStream.of(…) sẽ báo cáo đặc tính IMMUTABLE, thậm chí theo đặc điểm kỹ thuật, mà không thể bảo đảm rằng người gọi sẽ không sửa đổi mảng. Trừ khi chúng ta xem xét việc thiết lập một phần tử không phải là một sửa đổi cấu trúc, nhưng sau đó, toàn bộ sự phân biệt trở nên vô nghĩa một lần nữa, vì các mảng không thể được sửa đổi về mặt cấu trúc.

Và nó đã chỉ định rõ ràng không có đặc tính NONNULL. Mặc dù rõ ràng là các giá trị nguyên thủy không thể là null và các lớp Spliterator.Abstract<Primitive>Spliterator lúc nào cũng chèn một đặc tính NONNULL, trình tách biệt được trả về bởi Spliterators.spliterator​(long[],int,int,int) không được kế thừa từ Spliterator.AbstractLongSpliterator.

Điều xấu là, điều này không thể khắc phục được mà không thay đổi đặc điểm kỹ thuật, điều tốt là nó không có hậu quả gì.


Vì vậy, nếu chúng ta bỏ qua bất kỳ vấn đề với CONCURRENT, IMMUTABLE, hoặc NONNULL, mà không có hậu quả, chúng tôi có

SIZEDskip & limit. Đây là một vấn đề nổi tiếng, kết quả của cách thức skiplimit đã được API luồng thực hiện. Các triển khai khác có thể tưởng tượng được. Điều này cũng áp dụng cho sự kết hợp của một dòng vô hạn với một limit, mà nên có một kích thước có thể dự đoán, nhưng cho việc thực hiện hiện tại, đã không.

Kết hợp Stream.concat(…) với Stream.empty(). Nghe có vẻ hợp lý khi một luồng trống không không áp đặt các ràng buộc vào thứ tự kết quả. Nhưng hành vi phát hành lệnh của Stream.concat(…) khi chỉ có một đầu vào không có thứ tự, là vấn đề. Lưu ý rằng quá tích cực về thứ tự không có gì mới, hãy xem this Q&A về hành vi được xem là có chủ ý trước, nhưng sau đó đã được sửa vào cuối Java 8, cập nhật 60. Có lẽ, Stream.concat cũng đã được thảo luận ngay tại thời điểm này …

Hành vi của .boxed() rất dễ giải thích. Khi nó đã được thực hiện ngây thơ như .mapToObj(Long::valueOf), nó sẽ chỉ đơn giản là mất tất cả các kiến ​​thức, như mapToObj không thể giả định rằng kết quả vẫn được sắp xếp hoặc khác biệt. Nhưng điều này đã được sửa với Java 9. Ở đó, LongStream.range(0,10).boxed() có các đặc tính SUBSIZED|SIZED|ORDERED|SORTED|DISTINCT, duy trì tất cả các đặc điểm có liên quan đến việc triển khai.

+0

Cảm ơn bạn @ Holger. Hơi khó xử khi có nhiều đặc điểm không được duy trì. Tuy nhiên, nếu phần lớn nó cho * englishman để xem * (biểu hiện tiếng Bồ Đào Nha rằng mens nó chỉ cho show off), sau đó ít có vấn đề. Tôi đồng ý rằng các vấn đề có vấn đề là khi sử dụng 'Stream.concat' với' Stream.empty'. Và thứ hai là các luồng chưa được phân loại với 'giới hạn' hoặc' bỏ qua' được thảo luận trong https://stackoverflow.com/questions/27547519/most-efficient-way-to-get-the-last-element-of -a-stream/46562493 # 46562493. – Tet

+0

@ Holger nghiêm túc, đây là một câu trả lời tuyệt vời khác sẽ được tái sử dụng và liên kết lại nhiều lần tôi hy vọng. Hoàn toàn tuyệt vời! – Eugene

Các vấn đề liên quan