2015-12-09 4 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()); 

Счетчик ожиданий, вызов collect никогда не возвращается. Значение limit до filter дает ожидаемый результат. Зачем?Почему Stream.limit не работает в этом фрагменте?

+4

Кстати, вы можете использовать 'Stream.iterate (1, i -> i + 1) .filter (...) ...' вместо этого напуганного поставщика. –

+0

@AlexisC. Я не знал об этом API. Благодаря! – Vitaliy

+2

Или лучше, IntStream.range(). –

ответ

31

Поскольку в фильтрах всего 4 элемента, limit(10) никогда не достигает 10 элементов, поэтому конвейер Stream продолжает генерировать новые элементы и подавать их на фильтр, пытаясь достичь 10 элементов, которые проходят фильтр, но поскольку только первые 4 элемента пропускают фильтр, обработка никогда не заканчивается (по крайней мере до i переполнения).

Конвейер Stream не достаточно умен, чтобы знать, что больше элементов не может пройти фильтр, поэтому он продолжает обрабатывать новые элементы.

+0

Но, конечно же! :-) sneaky stuff .. – Vitaliy

+0

«Конвейер« Стрим »недостаточно умен, чтобы знать, что больше элементов не может пройти фильтр» ... и, действительно, [это не может быть] (https: //en.wikipedia. орг/вики/Halting_problem). – wchargin

25

Отражение limit и предложений filter имеет разные виды поведения.

Если поставить limit первый поток будет первым генерировать 10 целых чисел [1..10], а затем фильтровать их оставив только те меньше 5.

В первоначальном упорядочении с filter применяется первой , целые числа генерируются и фильтруются до тех пор, пока вы не достигнете 10 элементов. Это не бесконечный оператор, так как i в поставщике, в конечном счете, переполняется, но для достижения MAX_INT потребуется некоторое время, особенно на медленном компьютере.

+4

Я не рассматривал возможное переполнение int. +1 – Eran

+1

Возможно, речь идет о том, когда оптимизатор начинает свою работу, но на моей машине переполнение и последующее завершение операции происходит менее чем за секунду ... – Holger

16

Если вы хотите, чтобы остановить либо если число 5 достигает или 10 элементов собраны, есть Stream.takeWhile() метод, добавленный в 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

Он завершится, после перелива Поставщиком и начинает генерировать отрицательные числа. Полученный список будет содержать:

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

Причина этого в других ответах. На моей машине i7 потребовалось 40 секунд.

Смежные вопросы