2015-12-09 36 views
32
List<Integer> integer = Stream.generate(new Supplier<Integer>() { 
    int i = 0 ; 

    @Override 
    public Integer get() { 
     return ++i; 
    } 
}).filter(j -> j < 5) 
    .limit(10) // Note the call to limit here 
    .collect(Collectors.toList()); 

Phản đối kỳ vọng của tôi, cuộc gọi collect không bao giờ trở lại. Thiết lập limit trước khi filter tạo ra kết quả mong đợi. Tại sao?Tại sao Stream.limit không hoạt động như mong đợi trong đoạn mã này?

+4

Bằng cách này, bạn có thể sử dụng 'Stream.iterate (1, i -> i + 1) .filter (...) ...' thay vì nhà cung cấp sôi nổi này. –

+0

@AlexisC. Tôi không biết API này. Cảm ơn! – Vitaliy

+2

Hoặc tốt hơn, IntStream.range(). –

Trả lời

31

Vì chỉ có 4 phần tử vượt qua bộ lọc, nên limit(10) không bao giờ đạt 10 phần tử, do đó, luồng đường ống tiếp tục tạo ra các phần tử mới và cho chúng vào bộ lọc, cố gắng đạt 10 yếu tố vượt qua bộ lọc. 4 yếu tố đầu tiên vượt qua bộ lọc, quá trình xử lý không bao giờ kết thúc (ít nhất là cho đến khi i tràn).

Luồng phát trực tuyến không đủ thông minh để biết rằng không có thêm phần tử nào có thể vượt qua bộ lọc, do đó, nó tiếp tục xử lý các phần tử mới.

+0

Nhưng tất nhiên! :-) lén lút thứ .. – Vitaliy

+0

"Đường ống' Stream' không đủ thông minh để biết rằng không có nhiều phần tử nào có thể vượt qua bộ lọc "... và, quả thực, [nó không thể là] (https: //en.wikipedia. org/wiki/Halting_problem). – wchargin

25

Lật limit và các điều khoản filter có các hành vi khác nhau.

Nếu bạn đặt limit đầu tiên, dòng đầu tiên sẽ tạo ra 10 số nguyên [1..10], và sau đó lọc chúng chỉ để lại những nhỏ hơn 5.

Trong thứ tự ban đầu, với filter áp dụng đầu tiên , số nguyên được tạo và lọc cho đến khi bạn đạt đến 10 phần tử. Đây không phải là một toán tử vô hạn, vì i trong nhà cung cấp cuối cùng sẽ tràn, nhưng sẽ mất một lúc, đặc biệt là trên một máy tính chậm, để đạt được MAX_INT.

+4

Tôi đã không xem xét sự cố tràn vào cuối cùng. +1 – Eran

+1

Có thể đó là khi trình tối ưu hóa bắt đầu công việc của nó, nhưng trên máy của tôi, tràn và sau đó hoàn thành các hoạt động xảy ra trong vòng chưa đầy một giây… – Holger

16

Nếu bạn muốn dừng hoặc nếu số 5 là đạt hoặc 10 yếu tố này được thu thập, có Stream.takeWhile() phương pháp bổ sung trong Java-9:

List<Integer> integer = Stream.generate(new Supplier<Integer>() { 
    int i = 0 ; 

    @Override 
    public Integer get() { 
     return ++i; 
    } 
}).takeWhile(j -> j < 5).limit(10).collect(Collectors.toList()); 
9

Nó sẽ kết thúc, sau khi tràn Nhà cung cấp và bắt đầu tạo ra số âm. Danh sách kết quả sẽ chứa:

[1, 2, 3, 4, -2147483648, -2147483647, -2147483646, -2147483645, -2147483644, -2147483643] 

Lý do cho điều này là trong các câu trả lời khác. Trên máy i7 của tôi mất 40 giây để hoàn thành.

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