Đối với "lý do", tôi tin rằng có khá nhiều đối số trong nhận xét. Tuy nhiên, tôi đồng ý với bạn rằng nó khá khó chịu khi không có phương thức toList()
. Điều tương tự cũng xảy ra với phương thức toIterable()
.
Vì vậy, tôi sẽ chỉ cho bạn một mẹo cho phép bạn sử dụng hai phương pháp này. May mắn thay, Java là rất linh hoạt và cho phép bạn làm tất cả các loại công cụ thú vị. Khoảng 10 năm trước, tôi đọc this article, mô tả một thủ thuật dí dỏm để "cắm" các phương thức vào bất kỳ giao diện cụ thể nào. Bí quyết này bao gồm việc sử dụng proxy để điều chỉnh giao diện không có các phương thức bạn muốn. Trong những năm qua, tôi đã tìm thấy rằng nó có tất cả các ưu điểm của mẫu adapter, trong khi nó thiếu tất cả các khuyết điểm của nó. Đó là những gì tôi gọi là một việc lớn.
Dưới đây là một số mẫu mã, chỉ cần để hiển thị các ý tưởng:
public class Streams {
public interface EnhancedStream<T>
extends Stream<T> {
List<T> toList();
Iterable<T> toIterable();
}
@SuppressWarnings("unchecked")
public static <T> EnhancedStream<T> enhance(Stream<T> stream) {
return (EnhancedStream<T>) Proxy.newProxyInstance(
EnhancedStream.class.getClassLoader(),
new Class<?>[] {EnhancedStream.class},
(proxy, method, args) -> {
if ("toList".equals(method.getName())) {
return stream.collect(Collectors.toList());
} else if ("toIterable".equals(method.getName())) {
return (Iterable<T>) stream::iterator;
} else {
// invoke method on the actual stream
return method.invoke(stream, args);
}
});
}
public static void main(String[] args) {
Stream<Integer> stream1 = Stream.of(-2, 1, 2, -5).
filter(n -> n > 0).map(n -> n * n);
List<Integer> list = Streams.enhance(stream1).toList();
System.out.println(list); // [1, 4]
Stream<Integer> stream2 = Stream.of(-2, 1, 2, -5).
filter(n -> n > 0).map(n -> n * n);
Iterable<Integer> iterable = Streams.enhance(stream2).toIterable();
iterable.forEach(System.out::println); // 1
// 4
}
}
Ý tưởng là sử dụng một giao diện EnhancedStream
mở rộng giao diện Java Stream
bằng cách xác định phương pháp bạn muốn thêm vào. Sau đó, proxy động triển khai giao diện mở rộng này bằng cách ủy quyền các phương thức gốc Stream
cho luồng thực tế đang được điều chỉnh, trong khi nó chỉ cung cấp triển khai nội tuyến cho các phương thức mới (những phương thức không được xác định trong Stream
).
Proxy này có sẵn bằng phương tiện tĩnh minh bạch thực hiện tất cả nội dung proxy.
Xin lưu ý rằng tôi không nói rằng đây là giải pháp cuối cùng. Thay vào đó, nó chỉ là một ví dụ có thể được cải thiện rất cao, tức là đối với mọi phương thức Stream
trả về một số Stream
khác, bạn cũng có thể trả lại proxy cho phương thức đó. Điều này sẽ cho phép EnhancedStream
s bị xiềng xích (bạn cần phải xác định lại các phương pháp này trong giao diện EnhancedStream
, để chúng trả lại loại trả về tương đối EnhancedStream
). Bên cạnh đó, xử lý ngoại lệ thích hợp bị thiếu, cũng như mã mạnh hơn để quyết định có ủy quyền thực hiện các phương thức cho luồng gốc hay không.
tôi sẽ đặt câu hỏi ngược lại: tại sao 'toArray() 'thay vì' thu thập (toArray ()) '. Sự bùng nổ API là điều mà JDK có xu hướng chống lại càng nhiều càng tốt. Tôi hy vọng có được sự biện minh tốt cho 'toArray()'. –
Tại sao dừng lại trên 'toList'? Cho phép thêm 'toStack'' toSet' 'toMap'. – Pshemo
@MarkoTopolnik đúng, thx, tôi đã chỉnh sửa câu trả lời –