Tôi đang thêm câu trả lời thứ hai này dựa trên bản chỉnh sửa được đề xuất bởi người dùng srborlongan cho câu trả lời khác của tôi . Tôi nghĩ rằng kỹ thuật được đề xuất là thú vị, nhưng nó không thực sự phù hợp như là một chỉnh sửa cho câu trả lời của tôi. Những người khác đồng ý và đề xuất chỉnh sửa đã được bỏ phiếu xuống. (Tôi không phải là một trong những cử tri.) Tuy nhiên, kỹ thuật này có giá trị. Sẽ là tốt nhất nếu srborlongan đã đăng câu trả lời của riêng anh ấy / cô ấy. Điều này chưa xảy ra và tôi không muốn kỹ thuật bị mất trong sương mù của lịch sử chỉnh sửa StackOverflow bị từ chối, vì vậy tôi quyết định tự mình xem nó như một câu trả lời riêng biệt.
Về cơ bản, kỹ thuật này là sử dụng một số Optional
phương thức một cách thông minh để tránh phải sử dụng toán tử ternary ( ? :
) hoặc câu lệnh if / other.
Ví dụ nội tuyến của tôi sẽ được viết lại theo cách này:
Optional<Other> result =
things.stream()
.map(this::resolve)
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
.findFirst();
Một ví dụ của tôi sử dụng phương thức trợ giúp sẽ được viết lại theo cách này:
/**
* Turns an Optional<T> into a Stream<T> of length zero or one depending upon
* whether a value is present.
*/
static <T> Stream<T> streamopt(Optional<T> opt) {
return opt.map(Stream::of)
.orElseGet(Stream::empty);
}
Optional<Other> result =
things.stream()
.flatMap(t -> streamopt(resolve(t)))
.findFirst();
NHẬN XÉT
Hãy so sánh trực tiếp các phiên bản gốc với các phiên bản sửa đổi:
// original
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
// modified
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
Bản gốc là một cách tiếp cận đơn giản nếu người lao động: chúng ta có một Optional<Other>
; nếu nó có giá trị, chúng tôi trả về một luồng chứa giá trị đó và nếu nó không có giá trị, chúng tôi trả về một luồng trống. Khá đơn giản và dễ giải thích.
Việc sửa đổi là thông minh và có lợi thế là nó tránh được các điều kiện. (Tôi biết rằng một số người không thích toán tử ternary. Nếu sử dụng sai nó thực sự có thể làm cho mã khó hiểu.) Tuy nhiên, đôi khi mọi thứ có thể quá thông minh. Mã sửa đổi cũng bắt đầu với một Optional<Other>
. Sau đó, nó gọi Optional.map
được định nghĩa như sau:
Nếu có một giá trị, áp dụng hàm ánh xạ được cung cấp cho nó và nếu kết quả là không rỗng, hãy trả về Tùy chọn mô tả kết quả. Nếu không, trả lại một tùy chọn trống.
Cuộc map(Stream::of)
gọi trả về một Optional<Stream<Other>>
. Nếu một giá trị đã có trong tùy chọn đầu vào, Tùy chọn được trả về chứa Luồng chứa kết quả Khác. Nhưng nếu giá trị không có, kết quả là Tùy chọn trống.
Tiếp theo, cuộc gọi để orElseGet(Stream::empty)
trả về một giá trị của loại Stream<Other>
. Nếu giá trị đầu vào của nó là hiện tại, nó nhận được giá trị, đó là phần tử đơn Stream<Other>
. Mặt khác (nếu giá trị đầu vào không có) nó sẽ trả về một sản phẩm nào Stream<Other>
. Vì vậy, kết quả là chính xác, giống như mã điều kiện ban đầu.
Trong các ý kiến thảo luận về câu trả lời của tôi, liên quan đến chỉnh sửa bị từ chối, tôi đã mô tả kỹ thuật này là "ngắn gọn hơn nhưng cũng tối nghĩa hơn". Tôi đứng bên này Tôi phải mất một thời gian để tìm ra những gì nó đang làm, và tôi cũng mất một lúc để viết mô tả ở trên về những gì nó đang làm. Sự tinh tế quan trọng là sự chuyển đổi từ Optional<Other>
sang Optional<Stream<Other>>
. Một khi bạn mò mẫm điều này, nó có ý nghĩa, nhưng nó không rõ ràng đối với tôi.
Tuy nhiên, tôi sẽ thừa nhận rằng những thứ ban đầu tối nghĩa có thể trở thành thành ngữ theo thời gian. Nó có thể là kỹ thuật này kết thúc là cách tốt nhất trong thực tế, ít nhất là cho đến khi Optional.stream
được thêm vào (nếu nó đã từng).
CẬP NHẬT: Optional.stream
đã được thêm vào JDK 9.
.flatMap(Optional::toStream)
, với phiên bản của bạn, bạn thực sự thấy những gì đang diễn ra.