2014-05-02 16 views
9

Tôi có một danh sách các phần tử, tôi cần tìm phần tử đầu tiên thỏa mãn điều kiện, sau đó thoát bằng cách sử dụng các luồng Java 8.Luồng đã sắp xếp() trước khi findFirst() không còn lười biếng

Tôi nghĩ rằng đoạn mã sau không may đánh giá tất cả các yếu tố có sẵn mà không những gì tôi cần, tôi cần phải đánh giá từng mục một và stop (break) khi tìm ra trận đấu đầu tiên:

Tôi đang ở đây sắp xếp các các phần tử, sau đó ánh xạ phần tử đến thuộc tính url của nó rồi cố gắng lọc nếu url không rỗng hoặc rỗng sau đó tìm thấy kết quả phù hợp first!

Arrays.stream(dataArray) 
.sorted(Comparator.comparing(d -> d.getPriority())) 
.peek(o -> System.out.println("SORT: " + o)) 
.map(d -> d.getOriginalURL(shortUrl)) 
.peek(o -> System.out.println("MAP: " + o)) 
.filter(u -> u != null && !u.isEmpty()) 
.peek(o -> System.out.println("FILTER: " + o)) 
.findFirst().orElse(""); 

Nhưng đầu ra cho thấy, tất cả các mục được evaulated ngay cả khi là người đầu tiên phù hợp với hoạt động if điều kiện (filter).

Data[] data = new Data[] { new ParseData(), new InMemoryData() }; 
System.out.println(">>> " + getOriginalURL(data, "")); 

OUTPUT:

SORT: [email protected] 
MAP: InMemory URL 
FILTER: InMemory URL 
SORT: [email protected] 
MAP: Parse.com URL   <<< THIS SHOULD NOT HAPPEN 
FILTER: Parse.com URL  <<< AND THIS TOO 
>>> InMemory URL 

như được thấy trong đầu ra, dòng không chỉ dừng lại khi bộ lọc phù hợp với các yếu tố đầu tiên, thay vào đó nó tiếp tục đánh giá các yếu tố thứ hai quá!

tôi muốn làm như thế này:

Arrays.sort(dataArray, Comparator.comparing(d -> d.getPriority())); // sort 

for (Data data : dataArray) { 
    String url = data.getOriginalURL(shortUrl);   // map 
    if (url != null && !url.isEmpty()) {     // filter 
     System.out.println("url :" + url);    
     return url;         // find first 
    } 
} 

Trả lời

3

Các sorted hoạt động lực lượng traversal của tất cả các mục trong dòng.

Hoạt động của nhà nước, như phân biệt và sắp xếp, có thể kết hợp trạng thái từ các yếu tố đã xem trước đó khi xử lý các thành phần mới.

Hoạt động của nhà nước có thể cần xử lý toàn bộ đầu vào trước khi tạo kết quả. Ví dụ: một người không thể tạo bất kỳ kết quả nào từ việc phân loại một luồng cho đến khi một người xem tất cả các phần tử của luồng.

(Source)

Tôi không chắc chắn, tuy nhiên, lý do tại sao các hoạt động sau khi sorted cũng được thực hiện đối với tất cả các yếu tố trong suối.

Nếu bạn thực hiện sắp xếp một cách riêng biệt và sau đó sử dụng luồng cho phần còn lại của quá trình xử lý, quá trình xử lý sẽ dừng khi kết quả khớp đầu tiên được tìm thấy, như mong đợi.

Arrays.sort(dataArray, Comparator.comparing(d -> d.getPriority())); // sort 

Arrays.stream(dataArray) 
.peek(o -> System.out.println("SORT: " + o)) 
.map(d -> d.getOriginalURL(shortUrl)) 
.peek(o -> System.out.println("MAP: " + o)) 
.filter(u -> u != null && !u.isEmpty()) 
.peek(o -> System.out.println("FILTER: " + o)) 
.findFirst().orElse(""); 
11

Dưới đây là một ví dụ nhỏ để minh họa vấn đề này:

Stream.of("a", "ab", "abc", "abcd") 
    // .sorted() // uncomment and what follows becomes eager 
    .filter(s -> s.contains("b")) 
    .peek(s -> System.out.println("PEEK: " + s)) 
    .findFirst() 
    .orElse("X"); 

Đúng như dự đoán sản lượng là:

PEEK: ab 

Nếu dòng sorted là không chú thích, đầu ra là:

PEEK: ab 
PEEK: abc 
PEEK: abcd 

(Kết quả cuối cùng của toàn bộ đường ống là "ab" trong cả hai trường hợp, như mong đợi.)

Đúng là sorted phải tiêu thụ tất cả đầu vào của nó trước khi sản xuất phần tử đầu ra đầu tiên. Trong ý nghĩa đó, nó háo hức. Tuy nhiên, nó có vẻ lạ rằng nó ảnh hưởng đến cách các yếu tố được gửi xuống hạ lưu.

Không phân loại, hoạt động findFirst "kéo" các phần tử từ phía trên cho đến khi tìm thấy một phần tử và sau đó dừng lại. Với việc phân loại, hoạt động sorted() háo hức tập hợp tất cả các yếu tố, sắp xếp chúng và vì nó có tất cả chúng ngay tại đó, nó "đẩy" chúng xuống dòng. Tất nhiên, findFirst bỏ qua tất cả trừ phần tử đầu tiên. Nhưng điều này có nghĩa là các hoạt động can thiệp (chẳng hạn như bộ lọc) có thể làm việc không cần thiết.

Kết quả cuối cùng là chính xác nhưng hành vi không mong muốn. Điều này có thể được coi là một lỗi. Tôi sẽ điều tra và gửi một lỗi nếu thích hợp.

+0

Tôi đồng ý với bạn, đặc biệt nếu bất kỳ hoạt động nào trong số các hoạt động phát trực tuyến 'trung gian' là một hoạt động tốn kém. (trong câu hỏi của tôi, 'getOriginalURL' là một chi phí đắt tiền! –

+3

Đúng, lỗi hiệu suất. Đã ghi lại [JDK-8042355] (https://bugs.openjdk.java.net/browse/JDK-8042355). –

+2

@MuhammadHewedy Rất hay, Cảm ơn bạn đã nêu vấn đề này –

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