Почему Stream.limit не работает в этом фрагменте?
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
дает ожидаемый результат. Зачем?
Ответы
Ответ 1
Так как есть только 4 элемента, которые пропускают фильтр, limit(10)
никогда не достигает 10 элементов, поэтому конвейер Stream продолжает генерировать новые элементы и подавать их в фильтр, пытаясь достичь 10 элементов, которые проходят фильтр, но так как только первые 4 элемента пропускают фильтр, обработка никогда не заканчивается (по крайней мере до переполнения i
).
Конвейер Stream недостаточно умен, чтобы знать, что больше не может проходить фильтр, поэтому он продолжает обрабатывать новые элементы.
Ответ 2
Отбрасывание предложений limit
и filter
имеет разные типы поведения.
Если вы сначала поместите limit
, поток сначала сгенерирует 10 целых чисел [1..10], а затем отфильтрует их, оставив только те, которые меньше 5.
В исходном порядке, при первом применении filter
, целые числа генерируются и фильтруются до тех пор, пока вы не достигнете 10 элементов. Это не бесконечный оператор, так как i
в поставщике будет в конечном итоге переполняться, но для достижения MAX_INT
потребуется некоторое время, особенно на медленном компьютере.
Ответ 3
Если вы хотите остановить либо, если число 5 достигнуто, либо собрано 10 элементов, в Java-9 добавлен метод Stream.takeWhile()
:
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());
Ответ 4
Он завершится после того, как Поставщик переполнит и начнет генерировать отрицательные числа. Полученный список будет содержать:
[1, 2, 3, 4, -2147483648, -2147483647, -2147483646, -2147483645, -2147483644, -2147483643]
Причина этого в других ответах. На моей машине i7 потребовалось 40 секунд.