Đây có phải là một điều lành mạnh để trả lại Luồng bất cứ nơi nào chúng ta thường trả lại Bộ sưu tập không?


19

Trong khi phát triển API của tôi không bị ràng buộc với bất kỳ mã kế thừa nào, tôi thường thấy mình viết các phương thức hoàn toàn là đường truyền Streams bị chấm dứt bằng cách thu thập kết quả. Như cái này:

ImmutableSet<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfThing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey)
        .collect(MyCustomCollectors.toImmutableSet());
}

Bây giờ, hầu hết các máy khách của lớp này thường sẽ cần Bộ sưu tập (trong trường hợp này là Bộ không thay đổi) để tìm kiếm các phần tử và lặp lại trên nó, nhưng một số khách hàng có thể được hưởng lợi từ việc có Luồng để họ có thể đưa thêm một số hoạt động lên trên đó Truyền phát mà không cần lấy luồng mới từ Bộ sưu tập. Vì vậy, việc trả lại một luồng cung cấp cho các nhân viên một siêu lựa chọn mà họ sẽ có nếu họ chỉ có Bộ sưu tập (sau tất cả, họ luôn có thể collect()tự tạo Luồng:

Stream<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfthing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey);
        // No collect
}

Cách tiếp cận này rất hấp dẫn đối với tôi để thử vì tôi không thấy bất kỳ sai sót tiềm năng nào mà nó có thể có. Tuy nhiên, tôi chưa bao giờ thấy cách tiếp cận này trong bất kỳ thư viện nào (có lẽ vì không có nhiều thư viện được phát hành sau khi xuất hiện Java 8), vì vậy tôi hơi ngại khi áp dụng nó. Các lớp thư viện hiện có thường trả về Bộ sưu tập khi chúng lấy được thứ gì đó từ trạng thái riêng.

Có điều gì đó tồi tệ có thể xảy ra nếu tôi quyết định trả lại Luồng bất cứ nơi nào bản thân tiền Java-8 của tôi sẽ trả lại Bộ sưu tập không? Hoặc có lẽ tôi đang làm một cái gì đó của một antipotype ở đây với tất cả những gì xuất phát từ trạng thái riêng tư?

Câu trả lời:


14

Nếu myPrivateThingiescó thể thay đổi, bạn đã tạo một phụ thuộc ẩn giữa trạng thái riêng tư và kết quả truyền phát. Nếu khách hàng có thể gián tiếp gây ra myPrivateThingiesthay đổi trạng thái, thì anh ta sẽ nhận được một kết quả khác khi gọi collectso với kết quả ban đầu bạn dự định đưa ra.

Nếu myPrivateThingieskhông thay đổi, thì kết quả sẽ được minh bạch, nhưng có một vấn đề nữa bạn phải coi chừng: rác ngữ nghĩa , tức là giữ một lượng lớn bộ nhớ không còn cần thiết. Giả sử myPrivateThingieslà rất lớn và kết quả của việc thu thập luồng là nhỏ. Máy khách có thể giữ luồng lâu sau khi vứt bỏ tất cả các tham chiếu đến đối tượng đã tạo ra nó, nhưng điều đó streamvẫn không myPrivateThingiesbị thu gom rác. Háo hức thu thập kết quả sẽ cho phép myPrivateThingiesđược giải phóng.

Điều này thực sự đã xảy ra trước Java 7 khi gọi substring. Oracle đã quyết định rằng việc tiết kiệm hiệu quả tiềm năng từ việc không sao chép chuỗi con mỗi lần không đáng để đôi khi gây ngạc nhiên cho người dùng trung bình với mức tiêu thụ bộ nhớ quá mức. Điều đó không có nghĩa là không có trường hợp sử dụng thực sự cho hành vi cũ (ví dụ như trình phân tích cú pháp) nhưng thường thu thập kết quả một cách háo hức là đủ nhanh và khi điều đó xảy ra, bạn không có ưu điểm và tiềm năng.

Mặt khác, việc trả về một luồng cung cấp cho khách hàng khả năng chọn cấu trúc dữ liệu họ muốn sử dụng để giữ kết quả, trái ngược với việc bạn chọn một luồng cho anh ta. Nó có thể có giá trị cung cấp cả hai lựa chọn.


4

Điều quan trọng nhất cần xem xét: Streams chỉ có thể được lặp lại một lần, trong khi bạn linh hoạt hơn so với Collection: bạn có thể tiếp tục tạo thêm Streams hoặc thậm chí Iterators để thực hiện xử lý bổ sung, lặp đi lặp lại trên kết quả.

Vì vậy, nếu bạn không chắc chắn liệu người gọi phương thức sẽ sử dụng kết quả một lần và chỉ một lần hay không, tốt hơn là trả về a Collection.


Mã mẫu của bạn có một lỗi rõ ràng: tại sao một SocialStatuskhái niệm về một người , he?


3

Theo quan điểm của tôi, không. Những điều bạn có thể làm với các luồng là sự thay thế nghiêm ngặt những điều bạn có thể làm với các bộ sưu tập và thường chúng có thể được thực hiện hiệu quả hơn, vì vậy không có lý do gì để không sử dụng chúng ngoại trừ việc không quen thuộc. "Các biểu thức Lambda là thuốc cửa ngõ vào Java 8, nhưng Luồng là nghiện thực sự." (Venkat Subramaniam, Lập trình hàm trong Java )

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.